Enum Value Is Not Deserialized By WCF Service - c#

I built a WCF service and there's a section that looks like this:
[ServiceContract]
public class Service {
[OperationContract]
public SomethingElse[] Method(Code a, params Something[] b) { ... }
}
[DataContract]
public class Something {
[DataMember]
public string Stuff {get;set;}
[DataMember]
public Status MyStatus {get;set;}
public string ServerSideField {get;set;}
}
[DataContract]
public class SomethingElse {
[DataMember]
public Status MyStatus {get;set;}
}
[DataContract]
public enum Status {
[EnumMember] WorksFine,
[EnumMember] NotWorking
}
[DataContract]
public enum Code {
[EnumMember] TypeA,
[EnumMember] TypeB
}
Now I am using it as a service reference for a C# client. For some reason, whenever I call Method, the MyStatus property inside the b parameter is always set to WorksFine, even if I set it to NotWorking. On the other hand, whenever I pass Code.TypeA or Code.TypeB for the a argument, the service always deserializes it correctly.
For the sake of due diligence, other posts on the subject of passing enums to WCF services refer to DataContract, EnumMember(Value="TypeA"), and ServiceKnownType so I gave all of those a shot. However, even when I use ServiceKnownType (like below), I am still encountering the same problem.
[ServiceContract]
[ServiceKnownType(typeof(Something)]
[ServiceKnownType(typeof(Status)]
public class Service {
[OperationContract]
public SomethingElse[] Method(Code a, params Something[] b) { ... }
}
This issue seems unusually obscure for something so basic. I tested passing back Status.NotWorking from the service as well and the client is able to see it, so this appears to be a one-way issue. Any suggestions?
EDIT 1:
Similar issue: WCF not deserializing value types. Mysterious behaviour
EDIT 2:
Judging from the lack of immediate response, I am going to include some more information in case some of it sticks.
I'm experiencing this problem on both .NET 4.5 and 4.0.
The service is hosted on IIS, has SSL, and custom authentication scheme.
There is also a FaultContract attribute on Method but I excluded it to make the example simpler.
Event Viewer says zilch. So does IIS logs.
Auto-generated service reference code in Reference.cs looks like this:
The enum:
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18408")]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://schemas.datacontract.org/2004/07/Service")]
public enum Status{ TypeA, TypeB }
The method:
// CODEGEN: Parameter 'MethodResult' requires additional schema information that cannot be captured using the parameter mode. The specific attribute is 'System.Xml.Serialization.XmlArrayAttribute'.
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/Service/Method", ReplyAction="http://tempuri.org/Service/MethodResponse")]
[System.ServiceModel.FaultContractAttribute(typeof(MyClientProject.Service.MyFault), Action="http://tempuri.org/Service/MethodMyFaultFault", Name="MyFault", Namespace="http://schemas.datacontract.org/2004/07/Service.MyFault")]
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
MyClientProject.Service.Method Method(MyClientProject.Service.MethodRequest request);
EDIT 3:
I built another web service consisting of just the code above, but it does NOT reproduce the behavior that I am seeing. My conjecture is that either some other code is zilching the DataContractSerializer, OR there is some relevant IIS/WCF setting, OR some unresolved data contract issues.
I also built another web client that connects to both webservices, and it is receiving the same results as the first.
EDIT 4
Intercepted request with Fiddler and it looked like this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Method xmlns="http://tempuri.org/">
<a>TypeA</a>
<b><Something xmlns="http://schemas.datacontract.org/2004/07/TestService.Something">
<Stuff>mystuffvalue</Stuff>
</Something></b>
</Method>
</s:Body>
</s:Envelope>
So the enum is never being passed after all! How do I fix this contract mismatch?
EDIT 5
Forgot to mention that the web service had a reference to an ASMX service and was itself using XML serializer to communicate with that external service.

The key is here:
[System.ServiceModel.XmlSerializerFormatAttribute(SupportFaults=true)]
The XML Serializer is being used to generate the proxy instead of the DataContractSerializer. Did you accidentally specify the XmlSerializer? Are you trying to use an .asmx service?
Once you figure out what is causing the code to be generated using the XmlSerializer you'll have your answer, but it's not immediately evident from what you have posted.

For some unknown reason, the SOAP request made by the client was omitting the enum values that I needed, and consequently the server serialized those enums to their default values (the first enum definition on the list).
I fixed this issue by making omitted parameters required for the request body. This is the code that fixed it:
[DataContract]
public class Something {
[DataMember]
public string Stuff {get;set;}
[DataMember(IsRequired=true)] // just this 1 simple change!
public Status MyStatus {get;set;}
public string ServerSideField {get;set;}
}

Related

Interfaces not properly represent in proxy objects

Using many of the fine examples on this website, I have gotten my WCF service to properly serialize and deserialize concrete objects of interface types across the wire. Unfortunately, why seems to be lacking to me is client support.
A user has retrieved the meta-data from my service and is using that to auto-generate a service reference in visual studio 2012 with "add service reference". They are complaining that in their reference.cs (and thus in their auto-fill tool-tips), interfaces aren't coming across and are replaced by object.
For example, in my service interface code file:
[ServiceKnownType(typeof(ConcreteObject))]
...
[OperationContract]
bool WorkMethod(IMyInterface argument1);
...
but what they see is:
...
[OperationContract]
bool WorkMethod(object argument1);
...
As stated above, my client library works fine because I understand "object" really means "IMyInterface". But this is unclear to another client. How do you force the generated proxy objects to include interfaces, and properly represent the request type?
Thanks in advance!
Edit: Example interface, as per request.
public interface IMyInterface
{
bool DoWork(int i);
string SomeProperty { get; }
}
[DataContract]
[KnownType(typeof(IMyInterface))]
public class ConcreteObject : IMyInterface
{
//Working implementation here.
...
}

Why do my WCF class names have the parent class as part of their name?

I've been experimenting with Silverlight-Enabled WCF services and I'm getting a strange behavior that doesn't happen in the tutorial I was using. I create a simple operation contract like such: (yes, I know there is no interface with everything defined, it's something that the Silverlight-enabled template does)
[ServiceContract(Namespace = "")]
[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class TestService1
{
public class TestResponse
{
public string Hello { get; set; }
}
[OperationContract]
public TestResponse TestCall()
{
return new TestResponse();
}
}
Then I go and create a reference to it like I would a regular WCF service. But when I go to use my defined classes:
ServiceReference2.TestService1TestResponse test = new ServiceReference2.TestService1TestResponse();
Whereas I'm expecting ServiceReference2.TestResponse. Any idea why my parent class name is being concatenated onto the front of my datamember class names? I added a service reference to a plain console application and the same thing happens, so it's not a silverlight related thing.. maybe some setting in Silverlight-enabled WEC services? I watched this tutorial https://www.youtube.com/watch?v=8ln2LyWvf6Q to see if it happened for others, but it looks like the class names work fine there.
Out of luck I discovered what the issue was. I need to have the TestResponse class declared outside of the TestService1 class. I'm a little surprised the code generator for creating service references creates the classes in this way. I'd expect a ServiceReference2.TestService1.TestResponse instead, which is what threw me off so much.

WCF deserialization returning 0 list elements

I'm having some problems with deserializing an object.
I have following classes:
Metadatastore:
[DataContract]
public class MetadataStore : IEnumerable<ItemMetadata>
{
private List<ItemMetadata> data = new List<ItemMetadata>();
private string folderPath = null;
[DataMember]
public string FilePath
{
// getter and setter
}
[DataMember]
public List<ItemMetadata> Data
{
// getter and setter
}
}
ItemMetadata:
[Serializable()]
public class ItemMetadata
{
// syncid, syncversion, uristring etc..
}
The problem:
I'm transferring a Metadatastore object from my server(which has a wcf service running) to my client by using an output parameter. So serialization/deserialization of this output param is automatically done by wcf I suppose.
This is what happens:
the client calls the service:
service.GetChangeBatch(out metadatastore_object, otherValue);
the server responds correctly (metadatastore_object is filled and serialized successfully -> no errors)
the object I receive on client side though is not correct: the FilePath is filled correctly, but the List Data object contains zero elements! I checked also on the server and the data list contained 2 elements. Another strange thing to note is that it isn't either null, it's just a newly created empty list.
Does somebody has some experience with this, I can provide more code if needed.
Thanks in advance. Greets Daan
Use CollectionDataContract instead of DataContract.
Here the msdn's explanation about CollectionDataContract:
http://msdn.microsoft.com/en-us/library/aa347850.aspx
It could be this line:
private List<ItemMetadata> data = new List<ItemMetadata>();
That is emptying your list.
Also I would have marked ItemMetadata with DataContract and all properties with DataMember.
The ItemMetadata class should also be decorated as a DataContract so that the client has knowledge of the type and how to deserialize it.
You can also enable detailed message logging on wcf service to see what SOAP xml is coming back from the server.
You can then figure out if client is not deserialising xml to object correctly or server is not serialising object to xml correctly.
HTH

how to send an object to C# WCF service from PHP using SOAP

I'm having trouble sending a custom object thats defined as a datacontract in my WCF web service from PHP. I'm attempting to accomplish this via SOAP.
Here is what the dataContract looks like:
[DataContract]
public class simplyCustomer
{
[DataMember]
public int id;
[DataMember]
public string name;
[DataMember]
public string contact;
[DataMember]
public string street1;
[DataMember]
public string street2;
[DataMember]
public string city;
[DataMember]
...
}
So I have a function that takes simplyCustomer as parameter on WCF service. The php can receive simplyCustomer just fine using another function that returns one. However, if I call the one that accepts it using this code in PHP:
$retVal = $simplyService->__soapCall("addCustomer",array('parameters'=>$params));
The SOAP envelope that this call generates leaves the object NULL causing the WCF service to complain about null reference.
Here is the envelope that is generated:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://tempuri.org/"><SOAP-ENV:Body><ns1:addCustomer/></SOAP-ENV:Body></SOAP-ENV:Envelope>
The parameters should be where addCustomer is but there's nothing there.
Any help would be greatly appreciated!
Thanks!
I faced the same issue when building a private project.
My solution was to use T4 to generate service- and datacontract proxies, maybe you find it useful. Message me if you have any questions, the templates are not tested to their full extent.
You find the templates on github, including sample servicecontracts/datacontracts:
https://github.com/schaermu/wcf-phpclient-t4
feel free to fork the project!
cheers
Though this is asked while before, thought to add my input since I came accros the same issue.
Assuming your operation contract look something similar to
[OperationContract]
public <return_type> addCustomer(simplyCustomer parameters);
what you have suggested should work given that $params got all the required values set on initialisation where ever that has done and variable names are exactly similar to data contract.
Few tips going through this though.
1) If you have manage to send the object to the service, Could check the service logs to see what has gone wrong.
2) Just check your constructor to see all the parameters are set.
3) Also good to check that soap client is initialized and consumed properly.
eg : (following is, one of many possibilities)
$client = new Client( $baseUrl, array('soap_version' => SOAP_1_1,));
$result = $client->addCustomer(array("parameters" => $params ));
I had the same kind of problem. Cant see how you built your $params but I solved mine by doing this:
$username = "test";
$password = "test";
$input = array ("composite" => array("Password" => $password, "UserName" => $username));
$result=$client->__SoapCall('AuthenticateUser',array('parameters'=>$input));
My service method looks like this
[OperationContract]
AuthenticationData AuthenticateUser(AuthenticationData composite);
Using Fiddler is a good help when figuring out how to build your Soap stuff

How to add SoapExtension attribute to generated web service client proxy without modifying the generated class?

I have created a SoapExtension class to capture the soap request and response from specific web service calls. In order to put this SoapExtension into effect, I have to add an attribute to the method in the generated proxy client.
For example, I've added the AuditSoapCapture attribute to this method:
[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://blahblah.com/webservices/AddressSearch", RequestNamespace = "http://blahblah.com/webservices/", ResponseNamespace = "http://blahblah.com/webservices/", Use = System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
[blahblah.TriadLite.Core.AuditSoapCapture]
public System.Data.DataSet AddressSearch(string HouseNumber, string StreetName, string ZipCode) {
object[] results = this.Invoke("AddressSearch", new object[] {
HouseNumber,
StreetName,
ZipCode});
return ((System.Data.DataSet)(results[0]));
}
I am looking for a way to add this attribute to specific methods without modifying the generated client proxy, as they will get lost when we regenerate. Can I do this in a another partial class or interface or some other way?
Thanks!
Unfortunately, you'll need to modify the proxy code. The other possibilities you mention will not work - a parial class will not overwrite existing functionality, and there is no way that I'm aware of getting an interface to do what you need (compounded by the fact that there is no way to even let the proxy generator know that you intend to implement an interface).
Something that I've done in the past, in a situation where you have access to the source of the webservice, is to write a little app that will parse the code (as text) in the .asmx.cs file of the webservice to extract the names of all the methods that are tagged with [WebMethod]. Then the app "fixes up" the References.cs by inserting appropriate attributes onto the proxied methods, based on some settings file or somesuch. This works well because the naming conventions in the proxy map very neatly to the method names in the original service.
I may just end up injecting my SoapExtension by putting it into the Web.config. This will cause it to be run on every WS call without a client proxy method attribute. Then, I will modify the SoapExtension to look up the called WS method name on a list, and if it is on the list, then do the rest of the SoapExtension logic. I figure the hit on the list in this small volume application isn't going to kill performance.
6 years ago this was posted... So not sure if this will help anyone at this point.
I ran into something similar with a call to an old SOAP web service that had a dynamically generated proxy class that we didn't want to modify as it was auto-generated from the wsdl by the project. In order to solve this problem here is what we did.
The proxy class generated by wsdl.exe is a partial class. We extended this class like so to add a property with the information we wanted to access in the soapextension. You can add as many properties as you want...
partial class mysoapwebservice
{
public string myproperty{ get; set; }
}
in the web.config we registered the soap extension globaly on the project
<webServices>
<soapExtensionTypes>
<add type="MySoapExtension" priority="1" group="Low"/>
</soapExtensionTypes>
</webServices>
In the code were we created the web service object 'mysoapwebservice' we set the value of the property we needed.
In the soapextension you can get a reference to the web service that was called as well as the values. You can also determine the method call.
`
public class MySoapExtension: SoapExtension
{
public override void ProcessMessage(SoapMessage message)
{
switch (message.Stage)
{
case SoapMessageStage.BeforeSerialize:
{
// web service client object
var webserviceobject= ((SoapClientMessage)message).Client;
// method from web service that was called
var calledMethod = (SoapClientMessage)message).MethodInfo;
// checked the client type of webserviceobject and
//added method / property specific logic here
}
}
}
// other soap extension code
}
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class CriptoExtensionAttribute : SoapExtensionAttribute
[CriptoExtension]
public partial class MainService{

Categories

Resources