I have a common class (common meaning it is defined it its own library, used by both the client and service)
[Serializable]
Class C1
{
string s1;
string s2;
}
in my WCF service I create an instance, populate and return it:
this is the interface:
[ServiceContract]
public interface myInterface
{
[OperationContract]
c1 GetClass(string number);
}
here is my service class:
public class ColorTracker : myInterface
{
public c1 GetObj(string value)
{
c1 theColor = new c1();
c1.s1= "value1";
c1.s2= "value2";
return c1;
}
}
client:
using (ServieClient bmClient = new ServiceClient())
{
c1 theColor;
theColor = (c1) bmClient.GetObj("test");
}
It all kind of works, but I can only access the return data through the backing fields. I would like to instantiate the object (or i suppose it could be a structure since its only data, not state)
Thanks in advance.
WCF does not care about [Serializable] attribute. If you want you class to be a data contract, you should mark it with the [DataContract] attribute instead.
Also, convert your fields to properties, and mark them with the [DataMember] attribute.
[DataContract]
Class C1
{
[DataMember]
public string s1 {get;set;}
[DataMember]
public string s2 {get;set;}
}
When your attribute is [Serializable] then in the client side you can just use private fields! but,since your properties are Auto genenrated fiels {get;set;} ,in the client side you can see auto generated prop__BackingFields;
you can Refactor your properties like this:
[Serializable ]
public class MyData
{
private string _prop1;
public string Prop1
{
get { return _prop1; }
set { _prop1 = value; }
}
but I think the best way to code your issue is this:
1.Define two data contracts:
[DataContract ]
public class ServerSideFilledData
{...}and
[DataContract ]
public class ClientSideFilledData
{...}
2.Define a Message Contract with two MessageBody Attributes:
[MessageContract]
public class MixedServerandClientSideData
{
private ClientSideFilledData clientSideFilledData;
[MessageBodyMember]
public ClientSideFilledData ClientSideFilledData
{
get { return clientSideFilledData; }
set { clientSideFilledData = value; }
}
private ClientSideFilledData serverSideFilledData;
[MessageBodyMember]
public ClientSideFilledData ServerSideFilledData
{
get { return serverSideFilledData; }
set { serverSideFilledData = value; }
}
}
3.Instead of Serializable Or DataContract, use your Message for exchanging data between cient and server
[ServiceContract]
public interface IService1
{
[OperationContract]
MixedServerandClientSideData DoWork();
}
4.I think you know the continue ,initialize and fill your data in convenient sides.
Related
I have a base class with is inherited by multiple derived classes. I am initializing some properties of base class in constructor. Is there any way i can make the base class property being shared by my derived objects rather than creating the same property values for each derived class object. This is really important because some of the base class property values are generated by services and sharing this can improve performance.
Below is somewhat a simple blueprint of what i am trying to say:
public class ClassA
{
//i dont want to use static here as it will be shared for multiple codes
protected string country { get; set; }
public ClassA(string code)
{
country = CallsomeService(code);
}
}
public class ClassB : ClassA
{
public ClassB(string code) : base(code)
{
//blah blah
}
public void DomeSomethingWithCountry()
{
Console.WriteLine($"doing this with {country} in classB");
}
}
public class ClassC : ClassA
{
public ClassC(string code) : base(code)
{
//blah blah
}
public void DomeSomethingWithCountry()
{
Console.WriteLine($"doing soemthing else with {country} in classC");
}
}
Now making objects like below
public void test()
{
//call service for this
var classb=new ClassB("1");
//dont call service for this
var classc=new ClassC("1");
classb.DomeSomethingWithCountry();
classc.DomeSomethingWithCountry();
//call service for this as code is different
var classb1=new ClassB("2");
}
You could store the result of having made the call statically, rather than the value itself.
public class ClassA
{
static Dictionary<string,string> codeToCountryLookup
= new Dictionary<string,string>();
protected string country { get; set; }
public ClassA(string code)
{
if(!codeToCountryLookup.ContainsKey(code))
codeToCountryLookup.Add(code,CallsomeService(code));
country = codeToCountryLookup[code];
}
}
This is not in any way threadsafe, but should give you somewhere to start.
I have my WCF service returning data both in XML and JSON format.
One functios has to return a List, because I don't know which class will be used to fill this list.
So, I have my class:
public class WrapHome
{
public WrapHome() { }
private string p_TITOLO { get; set; }
public string TITOLO { get { return p_TITOLO.ToString(); } set { p_TITOLO = value; } }
private List<object> p_CHART { get; set; }
public List<object> CHART { get { return p_CHART; } set { p_CHART = value; } }
}
and my WCF declaration:
[OperationContract]
[WebGet(UriTemplate = "datiHome.xml?token={token}&p1={p1}&p2={p2}", ResponseFormat = WebMessageFormat.Xml)]
List<WrapHome> GetDatiHomeXML(string token, string p1, string p2);
The output is correctly set, but, when it has to return it converted in XML (or JSON), it re-calls the method and finally give the err_connection_reset error.
I know the problem is the List, because if I comment it, it works. How can I use my List in my WCF output?
If you need more details, ask me without any problem.
You could define
[KnownType(typeof(MyChildObject0))]
...
[KnownType(typeof(MyChildObjectM))]
public class MyBaseObject { ... }
public class MyChildObject0 : MyBaseObject { ... }
...
public class MyChildObjectM : MyBaseObject { ... }
Or you could add the attribute only once and define static method that returns all M+1 types at once.
and modify:
public class WrapHome
{
...
public List<MyBaseObject> CHART { get;set; }
}
In my case the solution is more simple.
I have a class that I return in all my mehotds, like this:
[DataContract]
public class Result
{
[DataMember]
public string KeyMensaje;
[DataMember]
public string ErrorMessage;
[DataMember]
public object Objeto;
...
}
The problem is due to Objeto object inside this class. This object is used to return variables types and it can't be serialized if is a complex object, for example:
res = new Result(list, "ok", "", "", "", null);
return res;
In this case object (list) is a list of other custom object, for example List<CustomEmployee>
The solution is add on top Result class the complex types that object can be, like this:
[DataContract]
[KnownType(typeof(List<CustomEmployee>))]
[KnownType(typeof(CustomEmployee))]
public class Result
{
...
}
To make it work, your service has to know the types it needs to serialize. If they cannot be found out by looking at your method's signature (for example because one type is object), you need to list all types that could possibly be in that object.
Annotate them to the top of your service class, if you list for example can have instances of foo, bar and baz:
[ServiceKnownType(typeof(foo))]
[ServiceKnownType(typeof(bar))]
[ServiceKnownType(typeof(baz))]
sI have one controller class, which is having private field of another class which is a model, model which gets data from xml deserialization. Because of this deserialization process I had to create public, parameterless constructor and some public fields-helpers which are simply processing data formats to another types. This processing is so simple that I don't want to re-write and XmlSerialization class using it's interface.
What I want to achieve is to have access to the fields from the model from the interface it inherits from only, but the model has to have public fields - how to hide some of them? They are in the same project. (Whole application is so tiny that dividing it to smaller pieces not always makes sense).
There is an example:
public class Program
{
public static void RequestHandler
{
public RequestHandler(string xmlRequest){
IRequest request = DataModel.ParseXml(xmlRequest);
//now user can use request from IRequest only
//but when he doesn't know that he has to use IRequest he can easily access and change
//values in DataModel properties, I want to prevent such possibility
}
}
}
public interface IRequest{
int test_id { get; }
DateTime description { get; }
IRequest ParseXml(string request);
bool Validate(IRequest request);
}
public class DataModel : IRequest {
[XmlElement("testId")]
int test_id { get; set; }
[XmlElement("testId")]
DateTime description { get; set; }
public DataModel() {} //this has to be specified to be allowed to use Serialization
//I don't want users to be able to use this constructor, however it has to be public
IRequest static ParseXml(string request){
// Xml Parsing process
}
bool Validate(IRequest request) {
//Process of checking if all data are available
}
}
Can you make your model as 'Internal' and expose all fields only via multiple interfaces and write another class which will expose your model objects via interface. e.g.
internal class DataModel : Interface1, Interface2 {
internal DataModel(_xml)
{
this.xml = _xml;
}
private xml {get; set;}
public Interface1.Property1 {get; set;}
public Interface2.Property2 {get; set;}
}
//expose DataModel only via below Helper class
public class DataModelHelper {
public Interface1 GetModel_1(string xml)
{
Interface1 i1 = new DataModel(xml);
return i1;
}
public Interface2 GetModel_2(xml)
{
Interface2 i2 = new DataModel(xml);
return i2;
}
}
I need invoke webservice operations using standard wsdl, but data objects must be different in client and in the server.
Using interfaces for data objects in a common library, making proxy classes for it in client and in server.
Then, I'm declaring operation contract using the interface, but WCF don't recognize it.
I yet tried use DataContractSerializerBehavior and set knownTypes, no success yet.
Someone can help-me? I've attached a complete solution with more details.
public interface Thing
{
Guid Id {get;set;}
String name {get;set;}
Thing anotherThing {get;set;}
}
[DataContract]
public class ThingAtServer: BsonDocument, Thing // MongoDB persistence
{
[DataMember]
Guid Id {get;set;}
//...
}
[DataContract]
public class ThingAtClient: Thing, INotifyPropertyChanged // WPF bindings
{
[DataMember]
Guid Id {get;set;}
//...
}
[ServiceContract]
public interface MyService
{
[OperationContract]
Thing doSomething(Thing input);
}
Click here do see a Sample project on GitHub with TestCases
I've created WCF Service with contract:
[OperationContract]
CompositeTypeServer GetDataUsingDataContract( CompositeTypeServer composite );
My CompositeTypeServer looks like this:
[DataContract( Namespace = "http://enes.com/" )]
public class CompositeTypeServer
{
[DataMember]
public bool BoolValue { get; set; }
[DataMember]
public string StringValue { get; set; }
}
Then I've created client project with type CompositeTypeClient:
[DataContract( Namespace = "http://enes.com/" )]
public class CompositeTypeClient
{
[DataMember]
public bool BoolValue { get; set; }
[DataMember]
public string StringValue { get; set; }
}
Then I've added the reference to my service and selected to reuse types. Everything worked like charm. I was able to use CompositeTypeClient on client side.
So the trick was to specify Namespace for DataContract so they would match on both client and service.
[DataContract( Namespace = "http://enes.com/" )]
PS. I can provide full working VS solution on request.
Based on ServiceKnownTypeAttribute (MSDN documentation), I changed what types expected depending on the situation. The main idea is implemented in the class XHelper, responsible to return the correct Type[] according to the situation:
public static class XHelper
{
public static Boolean? IsClient = null;
public static Type[] ClientTypes;
public static Type[] ServerTypes;
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider pProvider)
{
if (!IsClient.HasValue)
throw new Exception("Invalid value");
if (IsClient.Value)
return ClientTypes;
return ServerTypes;
}
}
You must include the ServiceKnownType tag in the interface that has the ServiceContract to know XHelper class.
[ServiceContract(Namespace = MyProxyProvider.MyNamespace)]
[ServiceKnownType("GetKnownTypes", typeof(XHelper))]
public interface MyService
{
[OperationContract]
Thing2 CopyThing(Thing1 input);
}
At the beginning of the test unit, which was informed of the right Type[] for every situation:
[AssemblyInitialize]
public static void TestInitialize(TestContext pContext)
{
XHelper.ClientTypes = new Type[] { typeof(Thing1ProxyAtClient), typeof(Thing2ProxyAtClient), typeof(Thing2ProxyAtClient) };
XHelper.ServerTypes = new Type[] { typeof(Thing1ProxyAtServer), typeof(Thing2ProxyAtServer), typeof(ThingNProxyAtServer) };
}
Click here do see the final code Sample project on GitHub with TestCases
I want to pass a class to a client over a WCF service. In that class I use a struct. But the value I receive at client side is: "System.Data.DataSet"
Must be something I don't understand.
See my struct (it's just a string for now)
namespace spine.datatypes
{
[Serializable]
public struct Tanga : IXmlSerializable
{
private string _value;
public Tanga(string value)
{
this._value = value;
}
public static implicit operator Tanga(string value)
{
return new Tanga(value);
}
public override string ToString()
{
return this._value;
}
// implement IXmlSerializable
public XmlSchema GetSchema() { return null; }
public void ReadXml(XmlReader reader)
{
_value = reader.ReadContentAsString();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteValue(this._value.ToString());
}
}
}
This is my service:
namespace webapplication.WCFservice.Recorder
{
[ServiceContract]
[XmlSerializerFormat]
public interface IWCFRecorder
{
[OperationContract]
TvRecorder getDedicatedJob(String recordername, String recorderip);
}
}
And this is the class I pass:
namespace spine.recorder.tv
{
[Serializable()]
[XmlRoot("Recorder")]
public class TvRecorder
{
public int id { get; set; }
public Tanga name { get; set; }
public MyIpAddress ip { get; set; }
public int channel { get; set; }
public MyTimecode time_start { get; set; }
public MyTimecode duration { get; set; }
public TvRecorder() { }
public TvRecorder(int _id, Tanga _name, MyIpAddress _ip, int _channel, MyTimecode _time_start, MyTimecode _duration)
{
this.id = _id;
this.name = _name;
this.ip = _ip;
this.channel = _channel;
this.time_start = _time_start;
this.duration = _duration;
}
}
}
There are unfortunately cases where svcutil generates a DataContract type and an XmlSerializer type for the same schema type. I suggest you try using the additional “/serializer:XmlSerializer /useSerializerForFaults” switches to svcutil and see if that resolves your issue. It should ensure that Tanga gets generated.
In general, for schema import to generate DataContract types, all of the types defined in the schemas must be contained in the subset of XSD that DCS supports, which you can find here:
http://msdn.microsoft.com/en-us/library/ms733112.aspx
If svcutil is failing to generate a proxy when you specify “/serializer:DataContractSerializer”, then the most likely explanation is that the schema isn’t DC-conformant. Do you see any other errors or warnings when you use svcutil?
It’s also generally bad practice to use DataSets (both typed and untyped) and IXmlSerializables in public web services. In this case, it seems there might be difficulties in importing these. Here’s a quick link for some other reasons it can be problematic: http://www.hanselman.com/blog/PermaLink,guid,d88f7539-10d8-4697-8c6e-1badb08bb3f5.aspx
While DataContractSerializer can serialize IXmlSerializable types, there is no guarantee at all made that IXmlSerializable types can be imported as data contracts. Those are two different concepts. IXmlSerializable types are free to provide their own schemas, so it's possible for them to provide schemas that are not datacontract-compliant and thus cause svcutil to fall back to XmlSerializer type generation.
Hope this helps.