I've been tasked with writing a WCF service. (have not done this before.) I've received the xsd of the xml that I'll be receiveing and i'm trying to translate this into a datacontract. I require help though.
An example of a portion of the xml is:
<tfsChequeId xmlns="http://www.something.com/XMLSchemas/itrs/tfs/v1">
<dic numericCode="20010411199194813505"/>
</tfsChequeId>
What I've done so far is:
[DataContract]
public class TFSChequeDic
{
[DataMember]
public string dic { get; set; }
}
How do I specify the numericCode attribute?
Any help would be gratefully received.
Kind Regards,
Fiona
UPDATE
A number of XSD's were provided to me. these are quite complex. On generating the datacontracts using svcutil.exe a number of errors were generated..
All of the following form:
Error: There was a validation error in the schemas provided for code generation:
Source:
Line: 85 Column: 6
Validation Error: Type 'http://www.something.com/XMLSchemas/itrs/common/v1:Docu
mentIdentifierCode' is not declared, or is not a simple type.
The generated datacontract is as follows:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="TfsChequeId", Namespace="http://www.something.com/XMLSchemas/itrs/tfs/v1")]
public partial class TfsChequeId : object, System.Runtime.Serialization.IExtensibleDataObject
{
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
private www.something.com.XMLSchemas.itrs.tfs.v1.TfsChequeIdDic dicField;
public System.Runtime.Serialization.ExtensionDataObject ExtensionData
{
get
{
return this.extensionDataField;
}
set
{
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public www.something.com.XMLSchemas.itrs.tfs.v1.TfsChequeIdDic dic
{
get
{
return this.dicField;
}
set
{
this.dicField = value;
}
}
}
However I've no idea how to use this.. ie set numericCode?
Any ideas/hints/tips would be gratefully received.
Fiona
You don't need to do it by hand. SvcUtil will generate a client proxy for you if you feed it the WSDL. Or are you creating the service itself?
Use the xsd tool to create a class object from the xsd provided.
Related
I'm seeing C# URI types serialized to JSON in an ODATA 3 controller in my WebAPI 2 project as an array of segments that does not include the domain. I've tried everything I can think of to change this (including fiddling with the serialization settings and even trying out the contract serializer instead of JSON.Net). Nothing seems to change the behavior. Note, I am not using .Net Core. Here is a code sample, condensed into a single snippet.
namespace WebApplication1.Controllers
{
public class MyObject
{
public Uri Url { get; set; }
public string Name { get; set; }
public string ID { get; set; }
}
public class MyObjectsController : ODataController
{
private static ODataValidationSettings _validationSettings = new ODataValidationSettings();
public IHttpActionResult GetMyObjects(ODataQueryOptions<MyObject> queryOptions)
{
try
{
queryOptions.Validate(_validationSettings);
return Ok<IEnumerable<MyObject>>(new List<MyObject>() { new MyObject() { ID="asdf", Name="123rwe", Url = new Uri("http://www.webapp.com/sites/page.html") } });
}
catch (ODataException ex)
{
return BadRequest(ex.Message);
}
}
}
}
This generates the following JSON in the browser:
{
"odata.metadata":"http://localhost:51607/odata/$metadata#MyObjects","value":[
{
"Url":{
"Segments":[
"/","sites/","page.html"
]
},"Name":"123rwe","ID":"asdf"
}
]
}
This is what I'd like (without changing the Url property to a string):
{
"odata.metadata":"http://localhost:51607/odata/$metadata#MyObjects","value":[
{
"Url":"http://www.webapp.com/sites/page.html","Name":"123rwe","ID":"asdf"
}
]
}
Any thoughts?
UPDATE:
Further research is suggesting that serialization behavior for URI types in WebAPI ODATA is controlled by the odataentityreferencelink and odataentityreferencelinkserializer classes. Specifically, URI type appear to be converted to odataentityreferencelink types which are then serialized in the manner I posted above (as an array of segments not including the root domain). I still need to know how to change this behavior, however the documentation for these two classes is not proving helpful. Last, I've confirmed this problem is not specific to the JSON output format. The serialization behavior for both XML/Atom and JSON are identical: URIs are broken down into an array of segments.
MS Premier support provided a final answer to this which I'll share below.
There is no option to directly JSON serialize an URI type, normally it would be broken into array of segments as you are observing in your code
The domain name will be eliminated as a normal scenario
The option you can go for is to create a custom URI Converter deriving from JSONConverter which is a part of Newtonsoft.Json namespace
I have my class structure for response as below:
/// <remarks/>
public System.Collections.Generic.List<PaymentMethods> DisallowedPaymentMethods
{
get
{
return this.disallowedPaymentMethodsField;
}
set
{
this.disallowedPaymentMethodsField = value;
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://blcorp.net/PaymentInfoInquiryService")]
public partial class PaymentMethods
{
private string paymentMethodField;
/// <remarks/>
public string PaymentMethod
{
get
{
return this.paymentMethodField;
}
set
{
this.paymentMethodField = value;
}
}
}
It's creating response as below
<DisallowedPaymentMethods>
<PaymentMethods>
<PaymentMethod>CreditCard</PaymentMethod>
</PaymentMethods>
<PaymentMethods>
<PaymentMethod>OnlineCheck</PaymentMethod>
</PaymentMethods>
</DisallowedPaymentMethods>
but I want response to be shown as below
<DisallowedPaymentMethods>
<PaymentMethod>CreditCard</PaymentMethod>
<PaymentMethod>OnlineCheck</PaymentMethod>
</DisallowedPaymentMethods>
How to create my response class to generate appropriate response structure.
If you're using Visual Studio, the easiest way to get a start is to copy the response as you want it into the clipboard, then use the "Paste XML as Classes" feature under the Edit => Paste Special menu.
Generate Class From JSON or XML in Visual Studio from C-Sharp Corner
Generating Data Type Classes from XML from Microsoft Documentation
If you're not using Visual Studio, you can also try Xml2Csharp.com
Try setting your return type to this and populating as appropriate:
public System.Collections.Generic.List<PaymentMethod> DisallowedPaymentMethods
Your class structure, without decorations indicating otherwise, dictates what your serialized response is. I think you class structure is a bit off.
I have a WCF service that implements a data contract. I then have a client that consumes that service with it's own implementation of the data contract.
If the data contracts don't match exactly, it doesn't generate any sort of error, nor does it return any data.
public class RecipeClient : ClientBase<IRecipeService>, IRecipeService
{
public RecipeEntity[] GetAllRecipes()
{
var recipe = Channel.GetAllRecipes();
return recipe;
}
}
In the above example, after the call is made, recipe contains an empty array of RecipeEntity.
I would expect it to not return any data, but why doesn't it generate an error?
It is for backward compatibility. If you add in datacontract of existing service some not required properties, all existing clients will work without errors.
As if was mentioned it's for backward compatibility, but you can mark some properties as required. And if there is no such property in a message, an exception will be thrown:
[DataContract]
public class Recipe
{
[DataMember]
public string Name { get; set; }
[DataMember(IsRequired = true)]
public string Rank { get; set; }
}
I have MVC project that relies on webservices to provide data and those webservices are based on CMIS specification with custom functionality. I have several classes used as DataContracts, which were created by Visual Studio when I added references to services I am calling. I am using that class as a model to ensure I am able to send instances to the service and process correctly those sent back to me.
I also have views to edit instances of those classes and I would like to use DataAnnotations to validate the forms (usually [Required] atribute and sometimes display name change).
I do not want to put those atributes in service reference files because updating the reference would mean I will loose those atributes (at least I could not be sure everything is still the same after reference update).
My thought was to create child class that would only serve as tool to introduce DataAnnotations to atributes I know for sure I will be using (those that will not dissapear from DataContract class for sure). How would I accomplish such inheritance with code?
Example - I have this class created by VS in reference.cs file:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="LibraryRequest", Namespace="http://schemas.datacontract.org/2004/07/Agamemnon.Models")]
[System.SerializableAttribute()]
public partial class LibraryRequest : DocuLive.RepositoryServiceExt.Library {
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string PasswordField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string ServerField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private bool UseDefaultField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string UserNameField;
[System.Runtime.Serialization.DataMemberAttribute()]
public string Password {
get {
return this.PasswordField;
}
set {
if ((object.ReferenceEquals(this.PasswordField, value) != true)) {
this.PasswordField = value;
this.RaisePropertyChanged("Password");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Server {
get {
return this.ServerField;
}
set {
if ((object.ReferenceEquals(this.ServerField, value) != true)) {
this.ServerField = value;
this.RaisePropertyChanged("Server");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public bool UseDefault {
get {
return this.UseDefaultField;
}
set {
if ((this.UseDefaultField.Equals(value) != true)) {
this.UseDefaultField = value;
this.RaisePropertyChanged("UseDefault");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string UserName {
get {
return this.UserNameField;
}
set {
if ((object.ReferenceEquals(this.UserNameField, value) != true)) {
this.UserNameField = value;
this.RaisePropertyChanged("UserName");
}
}
}
}
I want to make sure that no matter what changes in reference.cs file (even that class itself), I will always have Username, Password and Server marked as [Required] in my "Edit" and "Delete" forms.
Thanks in advance
Honza
I would stay away from inheriting an autogenerated class. It would not solve your problem with the attributes - you would have to override every single property so you can add attributes to it.
One solution is to use hand-coded datacontracts instead of autogenerated references. You will have full control over when they change, and you can put the attributes you need in them.
Another solution is wrapping the contract in your view model. Like this:
public class LibraryRequestViewModel {
private LibraryRequest request;
public LibraryRequestViewModel(LibraryRequest request){
this.request = request;
}
[Required]
public string Password {
get { return this.request.Password; }
set { this.request.Password = value; }
}
// do this for all fields you need
}
Apparently my education has failed me, because I didn't realize that methods in C# cannot be serialized. (Good to know.)
I am trying to create a WCF service that returns a simple class I created. The problem is that this simple class contains methods that I want to expose, and the caller of my service won't have any access to them (assuming they won't have a .dll containing the class declaration).
public class Simple
{
public string Message { get; set; }
private const string _Hidden = "Underpants";
public string Hidden
{
get { return _Hidden; }
}
public string GetHidden()
{
return _Hidden;
}
}
I set up a WCF service (let's call it MyService) to return an instance of my Simple class. To my frustration, I'm only getting a partial build of my class back.
public void CallService()
{
using (var client = new MyService.Serviceclient())
{
Simple result = client.GetSimple();
string message = result.Message; // this works.
string hidden = result.Hidden; // this doesn't.
string fail = result.GetHidden(); // Underpants remains elusive.
}
}
Is there any type of workaround where I'm able to set up a property or method on my class that will be accessible to whomever calls my service? How does one handle constants or other methods that are set up in a class that only exists in a service?
Typically you would create three different projects.
1. Service project
2. Client project
3. Data project
The Data project contains only the data classes - no application code. The methods and constants in these data classes should be independent of the Service/Client projects.
The Data project is included as a reference in both the Service and Client projects so that serialization and deserialization happen against the same binary - and you get to retain your constants/methods/etc.
The downside here is that all your clients will either have to be .NET apps, or you will have to provide different data libraries for each platform you wish to support.
As far as I know the only things that can be returned in a WCF service are primitives or a class with public properties that have a get method on them. From a high level WCF exists to allow you to specify a contract between the client and the server that it in theory transportation agnostic (ie you can swap out an HTTP endpoint for a netTcp endpoint and the service will function the same way from a contractual level).
The question to answer then is what data are you trying to pass back in this service call. If it's an object called simple with the data points of Message and Hidden then I would advise creating a data class called Simple that has those values as properties:
[DataContract]
public class Simple
{
[DataMember]
public string Hidden { get; set; }
[DataMember]
public string Message { get; set; }
}
When the client receives the response back Message and Hidden will be populated with whatever you have set their values to on the server side.
The DataMember attribute can only be used on properties and fields. This means that a WCF response can only serialize these types.
If you really want to only use the const in your WCF contract You could convert it to a field and place the DataMember attribute on it:
public class Simple
{
[DataMember]
public string Message { get; set; }
[DataMember]
public const string Hidden = "Underpants";
}
To be able to do this the field must be accessible (public).
Add the DataMember attribute to your property. To do so, you must have both a get and a set defined.
[DataMember]
public string Hidden
{
get { return _Hidden; }
set { }
}
technically you could do
public class thingToSerialize{
public Func<ArgType1,ArgType2...,ReturnType> myFunction{get;set;}
}
and then assign it a lambda that takes the arguments and returns the return type
before serializing