Given a WCF interface definition like this, is there a way to exclude a property from the ComplexObject response value?
I want to exclude the ChildObjects property. I don't want to remove the DataMember attribure from the property definition as I need it to be serialized in another case.
[ServiceContract]
public interface IComplexObjectService
{
[OperationContract]
ComplexObject Test(int a);
}
ComplexObject is defined something like this:
[DataContract(IsReference = true)]
public class ComplexObject
{
[DataMember]
public long ObjectCode
{
get { return _ObjectCode; }
set { _ObjectCode = value; }
}
[DataMember]
public List<ComplexObject> ChildObjects
{
get { return _ComplexObject; }
set { _ComplexObject = value; }
}
}
You are going to have to remove the DataMember attribute if you don't want to expose the ChildObjects property in your ComplexObject. If you have another use case which requires the ChildObjects then I suggest you have a separate ComplextObject which does have it. You cannot just switch it on or off at run-time as it will violate the contract definition.
[DataContract(IsReference = true)]
public class ComplexObject
{
public ComplexObject()
{
ChildObjects=null;
}
[DataMember]
public long ObjectCode
{
get { return _ObjectCode; }
set { _ObjectCode = value; }
}
[DataMember]
public List<ComplexObject> ChildObjects
{
get { return _ComplexObject; }
set { _ComplexObject = value; }
}
}
Related
When trying to map, I got this error:
Association references unmapped class: System.Object
My class:
public partial class MessageIdentifier
{
public virtual int ID { get; set; }
public virtual object Item { get; set; }
}
And the convention:
public class MyUsertypeConvention : IPropertyConvention
{
public void Apply(IPropertyInstance instance)
{
if (instance.Type.Name == "Object")
instance.CustomType<string>();
}
}
Kindly suggest how to map?
As a simple (quick, naive) solution - I would suggest to create and map real string property. And then let your setter and getter (or some AOP or listener) to do the "to/from string conversion":
public partial class MessageIdentifier
{
public virtual int ID { get; set; }
public virtual object Item
{
get { return ... my conversion from string; }
set { ItemString = ...my conversion to string; }
}
public virtual string ItemString { get; set; }
}
A smart and preferred (but a bit more challenging) is to create CustomType - which will hide that conversion and support REUSE. Check e.g. here
NHibernate Pitfalls: Custom Types and Detecting Changes
Creating and Testing a Custom NHibernate User Type
Not a satisfactory answer. It doesn't work with class that is generated from xsd by using XML. You can try the following:
public partial class MessageIdentifier
{
public virtual int ID { get; set; }
private object itemField;
public object Item
{
get { return this.itemField; }
set { this.itemField = value; }
}
}
I have written a wcf program where I have an class library where I declared the function which contains a class as a parameter.
I accessed that function in a client program but I don't know how to pass the class to that function. I will write the code below.
I have an interface which contains basic function declaration
In the class library there is another class it is implementing the interface. That interface contains a method which takes a class as parameter.
That class which is parameter contains properties.
[ServiceContract]
public interface ICarDetails
{
[OperationContract]
string updateCarDetails(Car c);
}
public class CarDetails : ICarDetails
{
public string updateCarDetails(Car c)
{
//some operations and initilizations
string example = Car.carno = "1234";
return "success";
}
}
Public class Car
{
private string carno;
private string carModel;
public string CARNO
{
get{ return carno; }
set{ carno = value; }
}
public string CARMODEL
{
get{ return carModel; }
set{ carModel = value; }
}
}
3) I will get access this function in myclient program where I consume. While consuming I need to send a class right? If so how can I send a class.
class Program
{
static void Main(string[] args)
{
CarDetailsserviceClient client = new CarDetailsserviceClient();
string abc = client.updateCarDetails(); // This shows error
}
}
public class carclient
{
public string carno = "6789";
}
I want to send this client class carclient to wcf service function updatecardetails.
You need to mark your Car type with the DataContract and DataMember attributes before you can pass it across the service boundary:
[DataContract]
public class Car
{
private string carno;
private string carModel;
[DataMember]
public string CARNO
{
get{ return carno; }
set{ carno = value; }
}
[DataMember]
public string CARMODEL
{
get{ return carModel; }
set{ carModel = value; }
}
}
If you do this then regenerate your service client, you will find you have access to the Car type from you calling code and you won't need to define your own type on the client side.
You can't pass a class, you must pass an object of that class. Create new object :
Car carclient = new Car() { CARNO = "6789" };
Then, pass it in argument :
string abc = client.updateCarDetails(carclient);
Car must be include in the DataContract like this :
[DataContract]
public class Car
{
private String carno;
private String carModel;
[DataMember]
public String CARNO
{
get { return this.carno; }
set { this.carno = value; }
}
[DataMember]
public String CARMODEL
{
get { return this.carModel; }
set { this.carModel = value; }
}
}
Our WCF service has just one method:
[ServiceContract(Name = "Service", Namespace = "http://myservice/")]
[ServiceKnownType("GetServiceKnownTypes", typeof(Service))]
public interface IService {
Response Execute(Request request);
}
public class Service : IService {
public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider provider) {
return KnownTypesResolver.GetKnownTypes();
}
public Response Execute(Request request) {
return new MyResponse { Result = MyEnumHere.FirstValue };
}
}
Both the Request and Response class includes a ParameterCollection member.
[Serializable]
[CollectionDataContract(Name = "ParameterCollection", Namespace = "http://myservice/")]
[KnownType("GetKnownTypes")]
public class ParameterCollection : Dictionary<string, object> {
private static IEnumerable<Type> GetKnownTypes()
{
return KnownTypesResolver.GetKnownTypes();
}
}
Subclasses of Request and Response store their values into the ParameterCollection value bag.
I am using the KnownTypesResolver class to provide type information across all Service objects.
public static class KnownTypesResolver {
public static IEnumerable<Type> GetKnownTypes()
{
var asm = typeof(IService).Assembly;
return asm
.GetAllDerivedTypesOf<Response>() // an extension method
.Concat(new Type[] {
typeof(MyEnumHere),
typeof(MyEnumHere?),
typeof(MyClassHere),
typeof(MyClassListHere),
});
}
}
If I'm not mistaken, everything should have proper type information for proxy class generation tools to produce well-defined classes client-side.
However, whenever one of the Response subclasses (i.e. MyResponse) contains an enum value such as MyEnumHere, WCF starts complaining that the deserializer has no knowledge of the MyEnumHere value. It should have. I provided a KnownTypeAttribute for this very reason.
The client-side proxy class does have a MyEnumHere enum in the Reference.cs file; the problem is that the ParameterCollection class has no KnownTypeAttributes generated for it.
I resorted to hand-editing and including the following lines in the generated Reference.cs file:
//>
[KnownTypeAttribute(typeof(MyEnumHere))]
[KnownTypeAttribute(typeof(MyEnumHere?))]
[KnownTypeAttribute(typeof(MyClassHere))]
[KnownTypeAttribute(typeof(MyClassListHere))]
//<
public class ParameterCollection : Dictionary<string, object> { /* ... */ }
Hand-editing generated files is horrible. But this makes the clients work. What am I doing wrong? How can I define my Service objects so that the VS-proxy classes that are generated are correct from the get-go?
Thanks for your time.
WCF does not work well with Dictionary because it is not interoperable. You may use Array, List or custom collection to make sure that your data is properly serialized.
Code below uses List<ParamCollectionElement> instead of Dictionary. I also removed some redundant attributes.
[DataContract]
public class Request
{
[DataMember]
public ParameterCollection ParameterCollection { get; set; }
}
[DataContract]
public class Response
{
[DataMember]
public ParameterCollection ParameterCollection { get; set; }
}
[DataContract]
public class MyResponse : Response
{
[DataMember]
public MyEnumHere Result { get; set; }
}
public class ParamCollectionElement
{
public string Key { get; set; }
public object Value { get; set; }
}
[CollectionDataContract(Name = "ParameterCollection")]
public class ParameterCollection : List<ParamCollectionElement>
{
}
public static class KnownTypesResolver
{
public static IEnumerable<Type> GetKnownTypes()
{
return
new Type[] {
typeof(MyEnumHere),
typeof(MyEnumHere?),
typeof(Request),
typeof(Response),
typeof(MyResponse)
};
}
}
[DataContract]
public enum MyEnumHere
{
[EnumMember]
FirstValue,
[EnumMember]
SecondValue
}
[ServiceKnownType("GetServiceKnownTypes", typeof(Service))]
[ServiceContract(Name = "Service")]
public interface IService
{
[OperationContract]
Response Execute(Request request);
}
public class Service : IService
{
public static IEnumerable<Type> GetServiceKnownTypes(ICustomAttributeProvider provider)
{
return KnownTypesResolver.GetKnownTypes();
}
public Response Execute(Request request)
{
var result = new MyResponse
{
Result = MyEnumHere.FirstValue,
ParameterCollection = new ParameterCollection()
};
result.ParameterCollection.Add(new ParamCollectionElement {Key = "one", Value = MyEnumHere.FirstValue});
result.ParameterCollection.Add(new ParamCollectionElement { Key = "two", Value = new Response() });
return result;
}
}
Make sure you have [DataContract] on your enum and [EnumMember] on each of the enum members:
[DataContract]
public enum MyEnumHere
{
[EnumMember]
SomeValue,
[EnumMember]
OtherValue,
[EnumMember]
OneMoreValue
}
That should cause the proxy-enum to be built out (with its member values) in your client without having to manually change the Reference.cs file.
I have the following class:
public class Widget {
public virtual int Id { get; set; }
[Required]
public virtual WidgetType Type { get; set; }
public virtual string SerializedParameters {
get {
return new XmlSerializer(Parameters.GetType()).Serialize(Parameters);
} set {
Parameters = new XmlSerializer(Assembly
.LoadFrom(Server.MapPath(Type.ModelAssembly))
.GetType(Type.ModelClass)
).Deserialize(value);
}
}
private object _parameters;
public virtual object Parameters {
get {
if (_parameters == null)
_parameters = Activator.CreateInstance(Assembly
.LoadFrom(Server.MapPath(Type.ModelAssembly))
.GetType(Type.ModelClass)
);
return _parameters;
} set { _parameters = value; }
}
}
The Parameters property is not mapped to the database but the SerializedParameters property is. However when it tries to get the information from the database and set the SerializedParameters (which subsequently sets the Parameters) the Type property is null and therefore an exception is thrown. I guess this depends on the order in which NHibernate sets the properties for the Widget but i can't get it to work.
I was wondering if there was a way around this. Appreciate the help. Thanks
moved the deserialization in the getter from the setter because as you said the type is not there yet
public class Widget
{
public virtual int Id { get; set; }
public virtual WidgetType Type { get; set; }
private string _serializedParameters;
private virtual string SerializedParameters {
get
{
return new XmlSerializer(Parameters.GetType()).Serialize(Parameters);
}
set
{
_serializedParameters = value;
}
}
private object _parameters;
public virtual object Parameters
{
get
{
if (_parameters == null)
{
if (!string.IsNullOrEmpty(serializedParameters))
{
// code to deserialize the Parameters and set to Parameters
_parameters = new XmlSerializer(Assembly
.LoadFrom(Server.MapPath(Type.ModelAssembly))
.GetType(Type.ModelClass)
).Deserialize(value);
}
else
{
// no existing parameters, then create new object
_parameters = Activator.CreateInstance(Assembly.LoadFrom(Server.MapPath("~/bin/" + widget.Type.ParametersAssembly + ".dll")).GetType(widget.Type.ParametersClass));
}
}
return _parameters;
}
set { _parameters = value; }
}
}
I am using a Generic Class as a Response Data Contract. All is good and this is streamlining the design of my WCF service significantly.
Each request is given a standard response object with the following signature:
Status (Enum)
Message (String)
Result (T)
Below is the Response Class:
[DataContract]
public class Response<T>
{
public Response() {}
public Response(T result)
{
this.result = result;
if (result != null)
{
this.status = Status.StatusEnum.Success;
}
else
{
this.status = Status.StatusEnum.Warning;
}
}
public Response(T result, Status.StatusEnum status)
{
this.status = status;
this.message = message;
}
public Response(T result, Status.StatusEnum status, string message)
{
this.status = status;
this.message = message;
this.result = result;
}
[DataMember]
public Status.StatusEnum status { get; set; }
[DataMember]
public string message { get; set; }
[DataMember]
public T result { get; set; }
}
And this works brillantly. Only problem I have is that the WCF Client is given a really crappy name for this object "ResponseOfAccountnT9LOUZL"
Is there a way to get around this issue?
Should I be using this class as just a Abstract class which is inherited?
I'd rather not have multiple classes cluttering my code.
Ok found the Answer
You can specify the Serialised version using the following syntax:
[DataContract(Name = "MyClassOf{0}{1}")]
class MyClass { }
So if I had a Class called Response which takes a Generic T parameter
I would use
[DataContract(Name = "ResponseOfType{0}")]
class Response { }
[DataContract(Name = "ReturnObjectOfType{0}")]
public class ReturnObject<T>
{....
//Iservice
[OperationContract]
ReturnObject<AdresKisiBilgi> BeldeAdresKisiBilgiSorgula(string tcKimlikNo);
//Service
public ReturnObject<HbysBusiness.MernisGuvenService.AdresKisiBilgi> BeldeAdresKisiBilgiSorgula(string tcKimlikNo)
{
return new MernisBiz().BeldeAdresKisiBilgiSorgula(tcKimlikNo);
}
client:
public ReturnObjectOfAdresKisiBilgi BeldeAdresKisiBilgiSorgula(string tcKimlikNo)
{....
Thank you Harry