null value return from WCF service operation - c#

I have a WCF service with an operation contract that returns null values. That is: it's supposed to return some custom class 'ProgressReport', but in the client application it shows up as null. In the WCF service itself the custom class is instantiated and returned without errors and without becoming null at any time.
The 'ProgressReport' class is not defined as DataContract because it is defined in another assembly.
For the operation that returns 'ProgressReport', the WcfTestClient informs me that it cannot perform operation because it uses type 'ProgressReport'.
I've tried adding an operationcontract with System.Object as return type, but it gives me the same error (cannot perform operation because it uses type 'System.Object')
Does anyone know how to solve this?

You could try to extend the ProgressReport-class (if it's not sealed) and define that as a DataContract (but I think that does not help with the properties of the class as they needed to be marked as DataMembers) or create a own class as a kind of a proxy and return this object:
[DataContract]
public class ProgressReportWcf : ProgressReport
{
}
or
[DataContract]
public class ProgressReportWcf
{
[DataMember]
public int Id { get; set; }
//aso...
public ProgressReportWcf(ProgressReport report)
{
Id = report.Id;
//aso...
}
}

Related

How to make readonly property in WCF? [duplicate]

I have a server side class which I make available on the client side through a [DataContract]. This class has a readonly field which I'd like to make available through a property. However, I'm unable to do so because it doesn't seem that I'm allowed to add a [DataMember] property without having both get and set.
So - is there a way to have a [DataMember] property without setter?
[DataContract]
class SomeClass
{
private readonly int _id;
public SomeClass() { .. }
[DataMember]
public int Id { get { return _id; } }
[DataMember]
public string SomeString { get; set; }
}
Or will the solution be use the [DataMember] as the field - (like e.g. shown here)? Tried doing this too, but it doesn't seem to care the field is readonly..?
Edit: Is the only way to make a readonly property by hacking it like this? (no - I don't want to do this...)
[DataMember]
public int Id
{
get { return _id; }
private set { /* NOOP */ }
}
Your "server-side" class won't be "made available" to the client, really.
What happens is this: based on the data contract, the client will create a new separate class from the XML schema of the service. It cannot use the server-side class per se!
It will re-create a new class from the XML schema definition, but that schema doesn't contain any of the .NET specific things like visibility or access modifiers - it's just a XML schema, after all. The client-side class will be created in such a way that it has the same "footprint" on the wire - e.g. it serializes into the same XML format, basically.
You cannot "transport" .NET specific know-how about the class through a standard SOAP-based service - after all, all you're passing around are serialized messages - no classes!
Check the "Four tenets of SOA" (defined by Don Box of Microsoft):
Boundaries are explicit
Services are autonomous
Services share schema and contract, not class
Compability is based upon policy
See point #3 - services share schema and contract, not class - you only ever share the interface and XML schema for the data contract - that's all - no .NET classes.
put DataMember attribute on a field not the property.
Remember thought, that WCF does not know encapsulation. Encapsulation is a OOP term, not a SOA term.
That said, remember that the field will be readonly for people using your class - anyone using the service will have full access to the field on their side.
I had some properties in a class in my service layer I wanted to pass over to Silverlight. I didn't want to create a whole new class.
Not really 'recommended', but this seemed the lesser of two evils to pass over the Total property to silverlight (solely for visual databinding).
public class PricingSummary
{
public int TotalItemCount { get; set; } // doesnt ideally belong here but used by top bar when out of store area
public decimal SubTotal { get; set; }
public decimal? Taxes { get; set; }
public decimal Discount { get; set; }
public decimal? ShippingTotal { get; set; }
public decimal Total
{
get
{
return + SubTotal
+ (ShippingTotal ?? 0)
+ (Taxes ?? 0)
- Discount;
}
set
{
throw new ApplicationException("Cannot be set");
}
}
}
There is a way to achieve this. But be warned that it directly violates the following principle cited in this answer:
"3. Services share schema and contract, not class."
If this violation does not concern you, this is what you do:
Move the service and data contracts into a separate (portable) class library. (Let's call this assembly SomeService.Contracts.) This is how you'd define an immutable [DataContract] class:
namespace SomeService.Contracts
{
[DataContract]
public sealed class Foo
{
public Foo(int x)
{
this.x = x;
}
public int X
{
get
{
return x;
}
}
[DataMember] // NB: applied to the backing field, not to the property!
private readonly int x;
}
}
Note that [DataMember] is applied to the backing field, and not to the corresponding read-only property.
Reference the contract assembly from both your service application project (I'll call mine SomeService.Web) and from your client projects (mine is called SomeService.Client). This might result in the following project dependencies inside your solution:
Next, when you add the service reference to your client project, make sure to have the option "reuse types" enabled, and ensure that your contract assembly (SomeService.Contracts) will be included in this:
VoilĂ ! Visual Studio, instead of generating a new Foo type from the service's WSDL schema, will reuse the immutable Foo type from your contract assembly.
One last warning: You've already strayed from the service principles cited in that other answer. But try not to stray any further. You might be tempted to start adding (business) logic to your data contract classes; don't. They should stay as close to dumb data transfer objects (DTOs) as you can manage.
Define the Service contract (Interface) Before implementing the contract using the class.

Error when calling Polymorphic method on WCF Client

This error comes as result of This previous question. I'm trying to call a polymorphic method from WCF client. This is my contract:
public interface IOhmioService
{
[OperationContract]
IEnumerable<Enumerador> GetEnumerador<T>() where T : IEnumerador, new();
}
This is my class implementation:
public class OhmioService : IOhmioService
{
public IEnumerable<Enumerador> GetEnumerador<T>() where T : IEnumerador, new()
{
T _obj = new T();
return _obj.Enumerar();
}
}
And call it from client like this:
public IEnumerable<Enumerador> Clients { get; set; }
Clients = this.serviceClient.GetEnumerador<Clientes>();
If i call this method from within the class everything works fine. But if i call it from WCF client a get this error:
The non generic Method 'Ohmio.Client.OhmioService.OhmioServiceClient.GetEnumerador()'
cannot be used with types arguments
What i'm i doing wrong? Thanks!
UPDATE
Ok. I try suggested solution, and get this Horrible error:
Type 'System.RuntimeType' wasn't spected with the contract name RuntimeType:http://schemas.datacontract.org/2004/07/System'. Trye to use DataContractResolver or add the unknown types staticaly to the list of known types (for instance, using the attribute KnownTypeAttribute or adding them to the list of known types to pass to DataContractSerializer)
Maybe using generic types over wcf is not such a good idea after all. I was trying to reduce repetitive code on the WCF service.
You cannot have generic OperationContract methods in a WCF ServiceContract. See here for further details: WCF. Service generic methods
You need to pass the type as a method parameter:
public interface IOhmioService
{
[OperationContract]
IEnumerable<Enumerador> GetEnumerador(string typeName);
}
public class OhmioService : IOhmioService
{
public IEnumerable<Enumerador> GetEnumerador(string typeName)
{
var type = Type.GetType(typeName);
var _obj = (IEnumerador)Activator.CreateInstance(type);
return _obj.Enumerar();
}
}
UPDATE
See update above; pass the fully qualified name of the type. That won't cause a serialization issue.

Hiding base class property using new keyword in WCF

I have a Scneario like this in my Server DLL class library.
[DataContract]
public class Base
{
[DataMember]
public string Info { get; set; }
}
[DataContract]
public class Child : Base
{
[DataMember]
public new int Info { get; set; }
public int Save()
{
}
}
My WCF Proxy at client side creates a Reference class. It Renames "Info" to "Info1". And shows proper properties in Base class.My code compiles great. So far so good. When I try to run ChildProxy.Save() from my client it gives me error Saying
"There was an error while trying to serialize parameter http://tempuri.org/:info. The InnerException message was 'Type 'ClientServiceLayer.InfoService.Info' with data contract name 'ArrayOfInfo:http://schemas.datacontract.org/2004/07/Info_DLL' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
"
How to hide the property of base class in WCF?
UPDATE:
Here is the call on the client-side
InvoiceServiceClient infoProxy = new InfoServiceClient();
invId = invfoProxy.Save();
As stated here:
You can't. Although the Child class is "hiding" the Info property of its base class, the attribute is being read by the serializer.
You could try adding [DataMember(Name = "Info")] to the child class and see what happens.
You could use KnownType Attribute in your DataContract
MSDN Data Contract Known Types

Serialization system.object

I'm trying to create a webservice to return a generic. The return class looks like this:
[Serializable]
public class RenderReturn
{
public RenderReturnStatus StatusReturn { get; set; }
public string MessageReturn { get; set; }
public string MessageTitle { get; set; }
public object **ObjectReturn** { get; set; }
}
Where ObjectReturn can be an object or a list of application objects, like cars, customers, etc..
But the webservice returns the following error:
System.InvalidOperationException: There was an error generating the XML document. --->
System.InvalidOperationException: The type Environment was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
at System.Xml.Serialization.XmlSerializationWriter.WriteTypedPrimitive(String name, String ns, Object o, Boolean xsiType)
This is possible or method should always return specific types?
Explicitly name your types. Otherwise one can put something in that isn't serializable.
Try something along these lines:
public class RenderReturn<T>
{
public T ObjectReturn {get;set;}
}
That way, at run-time, you'll have a concrete type rather than just System.Object.
Type of object is too generic for .NET to know what kind of object it is dealing with and how to deserialise. So it asks you to give it some hint by using XmlInclude attributes telling .NET the types to expect. In WCF you do the same: you use KnownType attribute to decorate properties.
Type object is not a good candidate for DTO objects that need to cross process boundaries.
In WCF or Web Services, try not to think in object-oriented fashion but think in WSDL. As far as WSDL is concerned you have a contract which explicitly defines the type of messages passed between client and server.

WCF issues with KnownType for Dictionary

I have a service that implements the following DataMember:
[DataMember]
public Dictionary<string, List<IOptionQueryResult>> QueryResultItems { get; set; }
I have the class "OptionQuerySingleResult" which inherits from IOptionQueryResult. Now, I understand that I need to make the OptionQueryResult type "known" to the Service and thus tried to add the KnownType in various ways:
[KnownType(typeof(Dictionary<string, OptionQuerySingleResult[]>))]
[KnownType(typeof(Dictionary<string, List<OptionQuerySingleResult>>))]
[KnownType(typeof(OptionQuerySingleResult)]
However, none of those approaches worked and on the client side I'm either getting that deserialization failed or the server simply aborted the request, causing a connection aborted error.
Does anyone have an idea on what's the proper way to get this to work?
I'd like to add that if I change the QueryResultItems definition to use the concrete type, instead of the interface, everything works just fine.
Thanks,
Tom
Edit:
The exception that I am getting is:
Error in line 1 position 524. Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:anyType' contains data from a type that maps to the name ':OptionQuerySingleResult'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'OptionQuerySingleResult' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.
However, when I look at the client proxy that svcutil generates, "OptionQuerySingleResult" is definitely defined in it:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="OptionQuerySingleResult", Namespace="")]
[System.SerializableAttribute()]
public partial class OptionQuerySingleResult : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged
I think you would use:
[KnownType(typeof(OptionQuerySingleResult)]
But you also need a [DataContract(Name = "OptionQuerySingleResult")] on your OptionQuerySingleResult class.
I think this also relies on your client proxy classes being generated by the SVCUTIL.EXE util.
You simply need to add the following property to your datacontract class.
[DataMember]
public object UsedForKnownTypeSerializationObject;
So now the generated proxy contains the Knowtypes you set on the datacontract.
I had the same problem and this is the only solution I came up with.
If you don't at the a property of type Object to you DataContract class,
the generated proxy doesn't contain the declared knowtypes
For example:
[DataContract]
[KnownType(typeof(List<String>))]
public class Foo
{
[DataMember]
public String FooName { get; set; }
[DataMember]
public IDictionary<String, Object> Inputs { get; set; }
[DataMember]
private Object UsedForKnownTypeSerializationObject{ get; set; }
}
It's not as pretty because you end up with a dummy property which doesn't have any
functional implementation. But then again I don't have another solution.

Categories

Resources