I have this generic class for my server responses:
[DataContract]
public class GenericResult<T>
{
public List<T> ListResult { get; set; }
public T Result { get; set; }
public string Message { get; set; }
}
and this GetAllBrandsTest method to return data to the client:
public async Task<GenericResult<Brand>> GetAllBrandsTest()
{
var result = await repo.GetAllAsync<Brand>();
return new GenericResult<Brand>()
{
ListResult = result.ToList(),
Message = "Success"
};
}
Everything is OK with this methods counterpart GetAllBrands:
public async Task<IList<Brand>> GetAllBrands()
{
return await repo.GetAllAsync<Brand>();
}
But when I call GetAllBrandsTest the result is empty.
[DataContract]
[KnownType(typeof(Brand))]
public class GenericResult<T>
{
[DataMember]
public List<Brand> ListResult { get; set; }
[DataMember]
public Brand Result { get; set; }
[DataMember]
public string Message { get; set; }
}
Any data type transferred between the server-side and the client-side should be explicitly specified how we serialize and deserialize it. Please use the DataContract attribute to specify the data structure the way how to serialize to XML so that the serialization and deserialization can work properly between the service-side and client-side. In addition, for unknown data types, please use the KnownType feature to specify the serialization method in advance.
[DataContract]
[KnownType(typeof(CircleType))]
[KnownType(typeof(TriangleType))]
public class CompanyLogo2
[DataMember]
private Shape ShapeOfLogo;
[DataMember]
private int ColorOfLogo;
}
[DataContract]
public class Shape { }
[DataContract(Name = "Circle")]
public class CircleType : Shape { }
[DataContract(Name = "Triangle")]
public class TriangleType : Shape { }
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-data-contracts
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-contract-known-types
We either decorate the class with both DataContract attribute and DataMember attribute or remove the DataContract attribute and DataMember attribute. Because the DataContract serializer will be used by default when the complex data type is without specifying any XML serializer.
Related
I'm creating objects to store the JSON data I will be receiving and cannot figure out the right way to structure the objects. Basically, I can be receiving two different objects that only have differences in the body, so I wish to make a base class.
public class SampleBase
{
public string url { get; set; }
public string resource { get; set; }
public string Body body { get; set; }
}
This is an example of the base, with the Body object declared below
public abstract class Body{ }
I then have two separate files for the versions of the base object I can receive, with an example below:
public class SampleObject : SampleBase
{
public class Body
{
public string bodyproperty { get; set; }
}
}
I am doing this just to be efficient with the classes since they share some properties. The SampleBase class will never be called, instead incoming json will be deserialized into SampleObject. Is this best practice?
Edit: Going by this example, the JSON is received as
{
"url": "xxxxxxxxxx",
"resource": "xxxxxxx",
"body": {
"bodyproperty": "xxxx",
}
}
Your class structure can heavily depend on your choice of serializer. For example, the DataContractJsonSerializer can technically handle inherited classes, but it does it in somewhat of a clunky way. You need to define all the known inheritors of your base type on the base type.
Personally, I would use composition rather than inheritance in your case. Here's an example using the DataContractJsonSerializer:
[DataContract]
public class Wrapper<T> where T : Body
{
[DataMember(Name = "url")]
public string Url { get; set; }
[DataMember(Name = "resource")]
public string Resource { get; set; }
[DataMember(Name = "body")]
public string T Body { get; set; }
}
[DataContract]
public class Body
{
[DataMember(Name = "bodyproperty")]
public string BodyProperty { get; set; }
}
Then you'd use the class like any other generic.
Wrapper<Body> obj = new Wrapper<Body>();
Edit: Since this is a MVC application, you'll likely be working with the JavascriptSerializer. The DataContract and DataMember can be ignored but the structure of the classes is still relevant.
var serializer = new JavaScriptSerializer();
var data = serializer.Deserialize<Wrapper<Body>>(json);
public abstract class AbstractSearch
{
public string Property { get; set; }
public string TargetTypeName { get; set; }
}
public class DateSearch : AbstractSearch
{
public DateTime? SearchTerm { get; set; }
public DateComparators Comparator { get; set; }
}
public enum DateComparators
{
Less,
LessOrEqual,
Equal,
GreaterOrEqual,
Greater,
InRange
}
public class SearchViewModel
{
public IEnumerable<AbstractSearch> SearchCriteria { get; set; }
}
How to pass above properties to SearchViewModel class from clientside JSON.
I need to pass Property, TargetTypeName, SearchTerm, Comparator from javascript to webapi through Json.
Iam using Web api 2.0 as Serverside. Is it possible to pass Json parameter into Inherited class?
If you specify the concrete type when serializing on the client-side you can make this work using TypeNameHandling. You specify the type using a $type property in the JSON.
The model-binder won't be able to instantiate an abstract-class.
Configure JSON.NET:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
Then post your JSON in this format:
{
"$type": "Namespace.DateSearch, AssemblyName"
"Property": "..."
"etc": ""
}
I have the following SOAP XML Response
<startProcessResponseDDWEBCall xmlns="http://eclipse.org/stardust/models/generated/OmniLinkServices">
<ProcessInstanceOid>13430</ProcessInstanceOid>
<Return>
<DDWEBCallResponseData>
<DDWEBCallOutput xmlns="http://www.infinity.com/bpm/model/OmniLinkServices/DDWEBCallOutput">
<CommonResponse xmlns=""/>
<reportContent xmlns=""><![CDATA[<HTML><BODY><P>The OmniPlus Host Server process DDWEB had the following error: </P><P><TEXT="FF000">E23 TX00087 Textfile not found: TestScript # 000003\\\ </TEXT></P><P>processing terminated</P></BODY></HTML>]]></reportContent>
</DDWEBCallOutput>
</DDWEBCallResponseData>
</Return>
</startProcessResponseDDWEBCall>
This is the SOAP body of a WCF web service call response. I have the following object hierarchy to represent the response
[DataContract(Namespace="http://www.infinity.com/bpm/model/OmniLinkServices/DDWEBCallOutput")]
public class OmniLinkExecuteScriptOutput
{
public string CommonResponse { get; set; }
[DataMember(Name = "reportContent")]
public string ReportContent { get; set; }
}
[DataContract(Namespace = "http://eclipse.org/stardust/models/generated/OmniLinkServices")]
public class OmniLinkExecuteScriptResponseData
{
[DataMember(Name="DDWEBCallOutput")]
public OmniLinkExecuteScriptOutput Output { get; set; }
}
[DataContract(Namespace = "http://eclipse.org/stardust/models/generated/OmniLinkServices")]
public class OmniLinkExecuteScriptReturn
{
[DataMember(Name="DDWEBCallResponseData")]
public OmniLinkExecuteScriptResponseData ReponseData { get; set; }
}
[MessageContract(WrapperName = "startProcessResponseDDWEBCall", WrapperNamespace = "http://eclipse.org/stardust/models/generated/OmniLinkServices", IsWrapped = true)]
public class OmniLinkExecuteScriptResponse
{
[MessageBodyMember(Name = "ProcessInstanceOid", Namespace = "http://eclipse.org/stardust/models/generated/OmniLinkServices")]
public string ProcessInstanceOid { get; set; }
[MessageBodyMember(Name = "Return", Namespace = "http://eclipse.org/stardust/models/generated/OmniLinkServices")]
public OmniLinkExecuteScriptReturn Return { get; set; }
}
The object OmniLinkExecuteScriptResponse is the return type of a method call. Everything is deserialized fine except for the inner most object, the object representing the DDWEBCallOutput node. I don't see any errors in the WCF plumbing, and the value of the Output property on the OmniLinkExecuteScriptResponseData object is always null.
Can anybody tell what I'm doing wrong?
Your problem is that you are applying the [DataContract(Namespace = "...")] attributes at the wrong level in your class hierarchy. This attribute controls the namespace to which all data members of an instance of a type are serialized, and in addition controls the root element namespace if the instance is being serialized as such.
Thus you need to do the following:
// Its members are in the empty namespace
[DataContract(Namespace = "")]
public class OmniLinkExecuteScriptOutput
{
[DataMember]
public string CommonResponse { get; set; }
[DataMember(Name="reportContent")]
public string ReportContent { get; set; }
}
// Its members are in the DDWEBCallOutput namespace
[DataContract(Namespace = "http://www.infinity.com/bpm/model/OmniLinkServices/DDWEBCallOutput")]
public class OmniLinkExecuteScriptResponseData
{
[DataMember(Name = "DDWEBCallOutput")]
public OmniLinkExecuteScriptOutput Output { get; set; }
}
// Its members are in the OmniLinkServices namespace
[DataContract(Namespace = "http://eclipse.org/stardust/models/generated/OmniLinkServices")]
public class OmniLinkExecuteScriptReturn
{
[DataMember(Name = "DDWEBCallResponseData")]
public OmniLinkExecuteScriptResponseData ReponseData { get; set; }
}
OmniLinkExecuteScriptResponse can remain unchanged.
Why I am getting OPERATION NOT SUPPORTED BY WCFTestClient because it is of type ...? (See screenshot)
The simillar method is working for normal plain contracts but not working for contract refering Entity Framework class
There are two Response DataContracts.
Plain data contract
[DataContract]
public class GetSomeResponseDataContract
{
private Collection myFund;
[DataMember]
public Collection<MyFund> MyFund
{
Get { }
}
}
Where MyFund is
[DataContract]
public class MyFund
{
[DataMember]
public string FundCode { get; set; }
[DataMember]
public string FundName { get; set; }
.
.
}
Data Contract with EntityDataContract
[DataContract]
public class GetYoursResponseDataContract
{
private Collection yourFund;
[DataMember]
public Collection<YoursFund> YourFund
{
Get { }
}
}
Where YourFund is
[EdmEntityTypeAttribute(NamespaceName="RModel1", Name="YoursFund")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class YoursFund : EntityObject
{
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String FundCode
{
get
{
return _FundCode;
}
set
{
OnFundCodeChanging(value);
ReportPropertyChanging("FundCode");
_FundCode = StructuralObject.SetValidValue(value, false);
ReportPropertyChanged("FundCode");
OnFundCodeChanged();
}
}
}
The following is a list of features not supported by WCF Test Client:
Types: Stream, Message, XmlElement, XmlAttribute, XmlNode, types that implement the IXmlSerializable interface, including the related XmlSchemaProviderAttribute attribute, and the XDocument and XElement types and the ADO.NET DataTable type.
Try Using Other Clients such as WCFStorm or Create a Proxy client and check
In your case, try to return the result as List Not as Collection
I need to write WCF service wich will take .xml file deserialize it into my custom calss and then do some operations on that data. I have written test version of this application which use console but not WCF. Here is how my code looks like:
[Serializable]
public class ErrorMsgElement
{
[XmlElement("Sender")]
public string SenderOfMessage{ get; set; }
[XmlElement()]
public Int64 UserID { get; set; }
[XmlElement()]
public Int64 SerialNumber { get; set; }
[XmlElement("DateTime")]
public DateTime DateAndTimeOfMessage { get; set; }
}
[Serializable]
[XmlRoot("Root")]
public class ErrorMessage
{
[XmlElement("Header")]
public string HeaderOfFile { get; set; }
[XmlElement("ErrorMsg")]
public ErrorMsgElement msgElent { get; set; }
}
And Main code
ErrorMessage myErrorMsg = new ErrorMessage();
//pathToFile is original path
string path = #pathToFile;
XmlSerializer myXmlSerializer = new XmlSerializer(typeof(ErrorMessage));
using (StreamReader myStrReader = new StreamReader(path))
{
myErrorMsg = (ErrorMessage)myXmlSerializer.Deserialize(myStrReader);
}
//some operations on myErrorMsg such as writing to database
It works fine in console application. Now I need to write same logic in WCF service. But I don't know what should I use - [Serializable], [DataContact], [MessageContract] or someting else?. Consider that I have some [XmlArray] atributes in my custom classes as well. And if I add [DataContract] atribute to my ErrorMessage class do I have to add same attribute to ErrorMsgElement as following?
[DataContract]
[Serializable]
public class ErrorMsgElement
{
...
}
[DataContract]
[Serializable]
[XmlRoot("Root")]
public class ErrorMessage
{
...
[DataMember]
[XmlElement("ErrorMsg")]
public ErrorMsgElement msgElent { get; set; }
}
All answers are well appreciated. Thanks in advance.
in wcf [DataContact] and DataContractSerializer are recommended for what do you want to do. But you can also use XmlSerializer as well it's really only your choice(using first or second don't making diffrent for performance of your application).
Edit:
When you adding DataContract attribute to your class than you don't have to add Serializable attribute too the same class DataContract is equal to Serializable
check this for answer about nested DataContracts