Problem with knowntype attribute in wcf - wcf

I'm having the following error in my wcf client.
NetDispatcherFaultException was unhandled.
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:GetVehicleResult. The InnerException message was 'Error in line 1 position 266. Element 'http://tempuri.org/:GetVehicleResult' contains data from a type that maps to the name 'http://schemas.datacontract.org/2004/07/WCFServer:Car'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'Car' 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.'. Please see InnerException for more details.
Can anyone help me where is the fault.
WCF Server
IVehicle
--------
[ServiceContract]
public interface IVehicleService
{
[OperationContract]
Vehicle GetVehicle(int type);
[OperationContract]
int GetNumberOfWheels(Vehicle vehicle);
}
VehicleService
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
public class VehicleService : IVehicleService
{
public Vehicle GetVehicle(int type)
{
switch (type)
{
case 0:
return new Car()
{
ID = 10,
Brand = "Volvo",
SteeringWheelPosition = "left"
};
case 1:
return new bike()
{
ID = 11,
Brand = "Scott",
HasFrontWheelBreak = true
};
case 2:
return new Kidsbike()
{
ID = 12,
Brand = "Kid Scott",
HasFrontWheelBreak = false,
HasSupportingWheels = true
};
default:
return null;
}
}
public int GetNumberOfWheels(Vehicle vehicle)
{
return vehicle.NoOfWheels;
}
}
abstract class
[KnownType(typeof(Car))]
[KnownType(typeof(bike))]
[DataContract]
public abstract class Vehicle
{
[DataMember]
public int ID { get; set; }
abstract public int NoOfWheels { get; }
[DataMember]
public string Brand { get; set; }
}
concrete classes
[DataContract]
public class Car : Vehicle
{
override public int NoOfWheels { get { return 4; } }
[DataMember]
public string SteeringWheelPosition { get; set; }
}
[KnownType(typeof(Kidsbike))]
[DataContract]
public class bike : Vehicle
{
override public int NoOfWheels { get { return 2; } }
[DataMember]
public bool HasFrontWheelBreak { get; set; }
}
[DataContract]
public class Kidsbike : bike
{
[DataMember]
public bool HasSupportingWheels { get; set; }
}
WCF Client
namespace WCFClient
{
[ServiceContract]
public interface IVehicleService
{
[OperationContract]
Vehicle GetVehicle(int type);
[OperationContract]
int GetNumberOfWheels(Vehicle vehicle);
}
}
namespace WCFClient
{
[KnownType(typeof(Car))]
[KnownType(typeof(bike))]
[DataContract]
public abstract class Vehicle
{
[DataMember]
public int ID { get; set; }
abstract public int NoOfWheels { get; }
[DataMember]
public string Brand { get; set; }
}
[DataContract]
public class Car : Vehicle
{
override public int NoOfWheels { get { return 0; } }
[DataMember]
public string SteeringWheelPosition { get; set; }
}
[KnownType(typeof(Kidsbike))]
[DataContract]
public class bike : Vehicle
{
override public int NoOfWheels { get { return 0; } }
[DataMember]
public bool HasFrontWheelBreak { get; set; }
}
[DataContract]
public class Kidsbike : bike
{
[DataMember]
public bool HasSupportingWheels { get; set; }
}
}
private void btnGetVehicle_Click(object sender, EventArgs e)
{
Car carObj = (Car)fclient.GetVehicle(0);
}
just creating proxy in client side . I can able to call the service successfully, but in response im having the problem. I try with Knowntype attribute. Whats wrong in this.

The following code work fine without error.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace WcfService1 {
[ServiceKnownType(typeof(Car))]
[ServiceKnownType(typeof(bike))]
[ServiceKnownType(typeof(Kidsbike))]
[ServiceContract]
public interface IVehicleService {
[OperationContract]
Vehicle GetVehicle(int type);
[OperationContract]
int GetNumberOfWheels(Vehicle vehicle);
}
[DataContract]
public abstract class Vehicle
{
[DataMember]
public int ID { get; set; }
abstract public int NoOfWheels { get; }
[DataMember]
public string Brand { get; set; }
}
[DataContract]
public class Car : Vehicle
{
override public int NoOfWheels { get { return 0; } }
[DataMember]
public string SteeringWheelPosition { get; set; }
}
[KnownType(typeof(Kidsbike))]
[DataContract]
public class bike : Vehicle
{
override public int NoOfWheels { get { return 0; } }
[DataMember]
public bool HasFrontWheelBreak { get; set; }
}
[DataContract]
public class Kidsbike : bike
{
[DataMember]
public bool HasSupportingWheels { get; set; }
}
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
public class VehicleService : IVehicleService
{
public Vehicle GetVehicle(int type)
{
switch (type)
{
case 0:
return new Car()
{
ID = 10,
Brand = "Volvo",
SteeringWheelPosition = "left"
};
case 1:
return new bike()
{
ID = 11,
Brand = "Scott",
HasFrontWheelBreak = true
};
case 2:
return new Kidsbike()
{
ID = 12,
Brand = "Kid Scott",
HasFrontWheelBreak = false,
HasSupportingWheels = true
};
default:
return null;
}
}
public int GetNumberOfWheels(Vehicle vehicle)
{
return vehicle.NoOfWheels;
}
}
}
Svc file:
<%# ServiceHost Language="C#" Debug="true" Service="WcfService1.VehicleService" CodeBehind="Service1.svc.cs" %>
Testing service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using WcfService1;
namespace Test {
class Program {
static void Main(string[] args) {
BasicHttpBinding hproxy = new BasicHttpBinding();
hproxy.MaxReceivedMessageSize = 2147483647;
hproxy.MaxBufferSize = 2147483647;
hproxy.MaxBufferPoolSize = 2147483647;
EndpointAddress eaddrr = new EndpointAddress("http://localhost:62807/Service1.svc");
ChannelFactory<IVehicleService> CFactoryobj1 = new ChannelFactory<IVehicleService>(hproxy, eaddrr);
IVehicleService isclientobj1 = CFactoryobj1.CreateChannel();
Car ve = (Car)isclientobj1.GetVehicle(0);
}
}
}

The KnownType should be used on the service contract interface itself not the vehicle class since it is the one that is returning the Vehicle object for one of its operations. Adding KnownType to the Vehicle class does nothing I think. because by default now, you don't need to add DataContract to your class for them to be useable in WCF. so you should have something like below.
[ServiceKnownType(typeof(Car))]
[ServiceKnownType(typeof(bike))]
[ServiceKnownType(typeof(Kidsbike))]
[ServiceContract]
public interface IVehicleService
{
[OperationContract]
Vehicle GetVehicle(int type);
[OperationContract]
int GetNumberOfWheels(Vehicle vehicle);
}

Related

How to Map DTO class to "Model" class In generic Repository

I use DTO class in API layer and I struggle to map DTO class to "model" class in generic Repository.cs in core layer.
Repository.cs :
namespace DTOMap.Core.Repository.Generic
{
public class Repository<T> : IRepository<T> where T : class
{
private DTOMapContext _context;
private DbSet<T> _table;
private IMapper _mapper;
public Repository(DTOMapContext context)
{
_context = context;
_table = _context.Set<T>();
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile<MyMapper>();
});
_mapper = config.CreateMapper();
}
public T Add(T obj)
{
// Here how to use My Mapper to save a book or an author generically
// Sth like :
// temp = _table.Add(_mapper.Map<T>(obj)); Here I want to map Dto to model to save in the db
// return = (_mapper.Map<T>(temp)); Here I want to map Model to DTO to collect it in API
// but I can't have a reference to TDTO
throw new NotImplementedException();
}
}
}
I show you the other classes that I find useful (I only implement Add function for this example and I am a beginner in .Net) :
Author.cs
namespace DTOMap.Core.Models
{
[Table("Author")]
internal class Author
{
[Key]
public int id { get; set; }
[Required, MaxLength(255)]
public string firstName { get; set; }
[Required,MaxLength(255)]
public string lastName { get; set; }
}
}
Book.cs
namespace DTOMap.Core.Models
{
[Table("Book")]
internal class Book
{
[Key]
public int id { get; set; }
[Required,MaxLength(255)]
public string name { get; set; }
[Required]
public int authorId { get; set; }
[Required]
public Author author { get; set; }
}
}
AuthorDTO.cs
namespace DTOMap.Domain.DTO
{
public class AuthorDTO
{
public int id { get; set; }
public string firstName { get; set; }
public string lastName { get; set; }
}
}
BookDTO.cs
namespace DTOMap.Domain.DTO
{
public class BookDTO
{
public int id { get; set; }
public string name { get; set; }
public int authorId { get; set; }
public AuthorDTO author { get; set; }
}
}
IRepository.cs
namespace DTOMap.Domain.Interface
{
public interface IRepository<T>
{
T Add(T obj);
}
}
MyMapper.cs
namespace DTOMap.Core
{
public class MyMapper : Profile
{
public MyMapper()
{
CreateMap<Book, BookDTO>();
CreateMap<BookDTO, Book>();
CreateMap<Author, AuthorDTO>();
CreateMap<AuthorDTO, Author>();
}
}
}
program.cs
... Some Fcts
builder.Services.AddTransient<IRepository<BookDTO>, BookRepository>();
builder.Services.AddTransient<IRepository<AuthorDTO>, AuthorRepository>();
... Some Fcts
If you need any other information, please ask me.

Serialization issue while returning object having collection of Navigation Objects

I am using WCF WebAPI for creating REST service and EF4. While returning an object(of POCO class) which is having NavigationProperty, I am getting following Serialization exception:
Cannot serialize member Models.Customer.Orders of type System.Collections.Generic.ICollection`1[[Models.Order, Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] because it is an interface.
Following is the POCO class
[Serializable]
[DataContract(IsReference = true)]
[KnownType(typeof(Order))]
public partial class Customer
{
#region Primitive Properties
[DataMember]
public virtual int CustomerID { get; set; }
[DataMember]
public virtual string CustomerCode { get; set; }
[DataMember]
public virtual string Description { get; set; }
[DataMember]
public virtual string Comments { get; set; }
[DataMember]
public virtual bool DeleteFlag { get; set; }
[DataMember]
public virtual byte[] RowVersion { get; set; }
#endregion
#region Navigation Properties
[DataMember]
public virtual ICollection<Order> Orders
{
get
{
if (_order == null)
{
var newCollection = new FixupCollection<Order>();
newCollection.CollectionChanged += FixupOrders;
_order = newCollection;
}
return _order;
}
set
{
if (!ReferenceEquals(_order, value))
{
var previousValue = _order as FixupCollection<Order>;
if (previousValue != null)
{
previousValue.CollectionChanged -= FixupOrders;
}
_order = value;
var newValue = value as FixupCollection<Order>;
if (newValue != null)
{
newValue.CollectionChanged += FixupOrders;
}
}
}
}
private ICollection<Order> _order;
#endregion
#region Association Fixup
private void FixupOrders(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (Order item in e.NewItems)
{
item.Customer = this;
}
}
if (e.OldItems != null)
{
foreach (Order item in e.OldItems)
{
if (ReferenceEquals(item.Customer, this))
{
item.Customer = null;
}
}
}
}
#endregion
}
The method in service is as follows:
[WebGet(UriTemplate = "Customer",
RequestFormat = WebMessageFormat.Xml,
ResponseFormat = WebMessageFormat.Xml)]
public List<Customer> Get()
{
CustEntities context = new CustEntities();
return context.Customer.Include("Orders").ToList();
}
Any help in above regard is highly appreciable.
Thanks
I don't think you can serialize Properties as interfaces in this way, otherwise the deserializer wouldn't know which concrete type to create when the object is deserialized.
Can you change your ICollection property to a concrete type like List<T>?

How to convert XAML File to objects

I have a xaml file that needs to convert into objects, Is there anyone done this before?
using (var stream = File.OpenRead(filename)) {
var yourObj = XamlReader.Load(stream);
}
//Configuration Class
namespace SKAT.Postfordeler.Shared.DataTypes
{
[Serializable]
public class PostFordelerConfiguration
{
private readonly ReceiverAddressList _receiverAddresses;
private readonly DocumentTypeList _documentTypes;
public PostFordelerConfiguration()
{
_receiverAddresses = new ReceiverAddressList();// I don't want to implement like this.
_documentTypes = new DocumentTypeList(); //// I don't want to implement like this.
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ReceiverAddressList ReceiverAddresses
{
get { return _receiverAddresses; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public DocumentTypeList DocumentTypes { get {return _documentTypes;} }
public static PostFordelerConfiguration Load(string location)
{
return (PostFordelerConfiguration)XamlReader.Load(new XmlTextReader(location));
}
}
}
//Document Entity
namespace SKAT.Postfordeler.Shared.DataTypes
{
[Serializable]
public class DocumentType
{
public String Id { get; set; }
}
}
//Document List
namespace SKAT.Postfordeler.Shared.DataTypes
{
[Serializable]
public class DocumentTypeList : List<DocumentType>{ }
}
//ReceiverAddress Entities
namespace SKAT.Postfordeler.Shared.DataTypes
{
[Serializable]
public class ReceiverAddress
{
public String Id { get; set; }
public String Routable { get; set; }
public String Description { get; set; }
}
}
//ReceiverAddress List
namespace SKAT.Postfordeler.Shared.DataTypes
{
[Serializable]
public class ReceiverAddressList : List<ReceiverAddress>{ }
}
// Load XAML file and Convert into objects
SKAT.Postfordeler.Shared.DataTypes.PostFordelerConfiguration loader =
Postfordeler.Shared.DataTypes.PostFordelerConfiguration.Load(
#"D:\projects\skatpostfordeler\SKAT.Postfordeler.Client.UI\PostfordelerConfiguration.xaml");

Inheritance resolved at runtime in protobuf-net

Is it possible to specify at runtime the sub-types of a specific abstract contract?
In the classic WCF/DataContract we have the KnownTypeAttribute and its constructor accepting a string representing the name of static function to invoke to get a set of Type:s.
[DataContract]
[KnownType("GetTypes")]
public abstract class AbstractContract
{
[DataMember] public int Prop1 { get; set; }
[DataMember] public string Prop2 { get; set; }
static IEnumerable<Type> GetTypes()
{
var list = new List<Type>();
list.Add(typeof(ConcreteContract1));
list.Add(typeof(ConcreteContract2));
return list;
}
}
[DataContract]
public class ConcreteContract1 : AbstractContract
{
[DataMember] public int Prop3 { get; set; }
}
[DataContract]
public class ConcreteContract2 : AbstractContract
{
[DataMember] public bool Prop3 { get; set; }
}
Is this scenario supported?
The scenario with GetTypes() isn't supported, partly due to how to v1 handles the generation/caching -however, in v2 (preview available) this is supoortable:
using System;
using System.Runtime.Serialization;
using ProtoBuf.Meta;
class Program
{
static void Main()
{
var model = TypeModel.Create();
var abst = model.Add(typeof(AbstractContract), true);
// define inheritance here...
abst.AddSubType(10, typeof(ConcreteContract1));
abst.AddSubType(11, typeof(ConcreteContract2));
model.CompileInPlace();
AbstractContract foo = new ConcreteContract1 { Prop1 = 123, Prop2 = "abc", Prop3 = 456 };
AbstractContract bar = (AbstractContract)model.DeepClone(foo);
Console.WriteLine(bar.Prop1);
Console.WriteLine(bar.Prop2);
Console.WriteLine(((ConcreteContract1)bar).Prop3);
}
}
[DataContract]
public abstract class AbstractContract
{
[DataMember(Order=1)]
public int Prop1 { get; set; }
[DataMember(Order=2)]
public string Prop2 { get; set; }
}
[DataContract]
public class ConcreteContract1 : AbstractContract
{
[DataMember(Order=1)]
public int Prop3 { get; set; }
}
[DataContract]
public class ConcreteContract2 : AbstractContract
{
[DataMember(Order=1)]
public bool Prop3 { get; set; }
}
Actually, with this approach you can take away all the attributes if you want (telling it explicitly instead). Note: you should cache and re-use the compiled model as far as possible - it is thread-safe, but generating it each time will be a bit more expensive.

wcf serialization problem

I have a type MyParameter that i pass as a parameter to a wcf service
[Serializable]
public class MyParameter : IXmlSerializable
{
public string Name { get; set; }
public string Value { get; set; }
public string Mytype { get; set; }
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
XElement e = XElement.Parse(reader.ReadOuterXml());
IEnumerable<XElement> i = e.Elements();
List<XElement> l = new List<XElement>(i);
Name = l[0].Name.ToString();
Value = l[0].Value.ToString();
Mytype = l[0].Attribute("type").Value.ToString();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteStartElement(Name);
writer.WriteAttributeString("xsi:type", Mytype);
writer.WriteValue(Value);
writer.WriteEndElement();
}
#endregion
}
The service contract looks like this:
[ServiceContract]
public interface IOperation
{
[OperationContract]
void Operation(List<Data> list);
}
Where data defines a data contract
[DataContract]
public class Data
{
public string Name { get; set; }
public List<MyParameter> Parameters{ get; set; }
}
When I run the service and test it
I get rhe exception in readXml of MyParameter
"the prefix xsi is not defined"
xsi should define the namespace "http://w3.org/2001/xmlschema-instance"
How do I fix the problem
I am very new to this so a sample code will be very very very helpful
thanks
Add:
writer.WriteAttributeString("xmlns","xsi", null,#"http://w3.org/2001/xmlschema-instance");