I have solution with 3 projects:
1. Client (reference: DataContracts and ServiceReference created via Visual Studio 2012 with name TaskerWcfService)
2. DataContracts
3. WCF Service (DataContracts)
First I've created WCFService and in DataContracts was only one class:
[DataContract]
public class WorkItem
{
[DataMember]
public Int64 Id { get; set; }
[DataMember]
public String Title { get; set; }
[DataMember]
public String Description { get; set; }
[DataMember]
public String ItemType { get; set; }
}
Then, I've created a Client with a ServiceReference (with name: TaskerWcfReference) and namespace for the WorkItem class has been - DataContracts lib.
And finally, I've extended WCF Service and DataContracts with additional class:
public class InfoData
{
[DataMember]
public Guid Id { get; set; }
[DataMember]
public String Value { get; set; }
[DataMember]
public Int32 Order { get; set; }
[DataMember]
public bool IsDefault { get; set; }
}
But when I've updated the ServiceReference I found that InfoData class was inside of the automatically generated proxy and it's namespace is: TaskerWcfReference.InfoData.
Why the classes described in similar way - placed in different places?
The functions of the service contracts return Generic.List and T in same way. Descriptions of the service contracts are similar too.
Related
Im working on ASMX service that allows me to work with databases and their tables. The schema looks like this
[DataContract]
public class DataBase
{
[DataMember]
public string Name { get; set; }
[DataMember]
public List<Table> Tables { get; set; }
...
}
[DataContract]
public class Table
{
[DataMember]
public string Name { get; set; }
[DataMember]
public List<Column> Columns { get; set; }
[DataMember]
public List<List<object>> Data { get; set; }
...
}
[DataContract]
public class Column
{
[DataMember]
public string Name { get; set; }
[ DataMember]
public string Type { get; set; }
...
}
"Data" field is meant to keep a table of all values of different types. The problem is - i have to work with a few of custom types:
public class Email
{
[DataMember]
public string address { get; set; }
...
}
public class Strings : List<string>
{
public Strings(IEnumerable<string> collection) : base(collection) { }
...
}
And the problem is that web service does not create references to these types. I do not use them in methods explicitly, but store in table. Using KnownType and DataContract did not help me, and when i created same classes in a client app, i have exceptions. Please, help?
I fixed it: basically i created dummy methods that returned object of nedded types, deleted the method references from client app and it worked.
I am new to WCF; this is my first try.
I created two projects using the Microsoft Visual Studio Express 2013 for Web. One is "WCF Service Application" and the other is a MVC Web application; the Web application consumes the WCF service.
I know the basics of making the communication possible between the Web application and the WCF service.
I will jump directly to to problem;
If I've two model classes represent two entities from the Database:
Stock:
public partial class Stock
{
public int Id { get; set; }
public string Name { get; set; }
public Nullable<int> UserId { get; set; }
public virtual User User { get; set; }
}
User:
public partial class User
{
public User()
{
this.Stocks = new HashSet<Stock>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Stock> Stocks { get; set; }
}
I need to map them to the WCF service correctly as [DataContract] classes; How?
This is my try:
[ServiceContract]
public interface IService1
{
// List all Stocks
[OperationContract]
List<Stock> GetStocks();
}
[DataContract]
public class WCF_Stock
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public Nullable<int> UserId { get; set; }
[DataMember]
public virtual WCF_User User { get; set; }
}
[DataContract]
public class WCF_User
{
// Does this constructor require any special attributes?
public WCF_User()
{
this.WCF_Stocks_Collection = new HashSet<WCF_Stock>();
}
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public virtual ICollection<WCF_Stock> WCF_Stocks_Collection { get; set; }
}
Please Note the comment question above: Does this constructor require any special attributes?
Implementation for IService1:
public class Service1 : IService1
{
private StockPEntities dbStock = new StockPEntities();
public List<Stock> GetStocks()
{
return dbStock.Stocks.ToList<Stock>();
}
}
I consume it in the Web application:
public class WCFConsumerController : Controller
{
ServiceReference1.Service1Client wcfService = new ServiceReference1.Service1Client();
public ActionResult Index()
{
return View(wcfService.GetStocks());
}
}
It gives An existing connection was forcibly closed by the remote host
But; before adding the User entity to the database, and of course before adding the WCF_User [DataContract] to the WCF Service; that is when there was only the WCF_Stock alone, like this:
[DataContract]
public class WCF_Stock
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
}
The code at the Web application that consumes the WCF service works correctly; that is, this line returns a View with Data:
return View(wcfService.GetStocks());
You don't have to create separate WCF_Stock class, and you don't have to mark classes using attributes.
I think that you have problem with lazy loading mechanism in Entity Framework. Try to disable it in GetStocks method using following code:
dbStock.Configuration.LazyLoadingEnable = false;
I am new to WCF and facing some issue. I have three project WCFClient,WCFService,CommonModel
CommonModel :- Have below classes
public class Room: INotifyPropertyChanged
{
int roomID;
public virtual int roomID_PK { get; set; }
public Room()
{
Row1Details = new RoomRowDetails();
Row2Details = new RoomRowDetails();
}
}
[Serializable]
public class RoomRowDetails : ISerializable, INotifyPropertyChanged
{
public RoomRowDetails()
{
RoomColor = "White";
RowSaleAmount = "";
}
....
}
WCFClient : is having client proxy class.
WCFService: Have ServiceContract OperationContract DataContract and have below class :-
[DataContract()]
[ServiceKnownType(typeof(Room))]
[ServiceKnownType(typeof(RoomRowDetails))]
public class RequestData
{
[DataMember]
public string ClientName { get; set; }
[DataMember]
public bool isServer { get; set; }
[DataMember]
public bool isSuccess { get; set; }
[DataMember]
public Room room { get; set; }
[DataMember]
public RoomRowDetails roomrow{ get; set; }
}
In both the project CommandModel project is added as a reference. Client proxy is generated properly but when run the project. I got below error:-
There was an error while trying to serialize parameter http://tempuri.org/:eventData. The InnerException message was 'Type 'CommonModel.MODELS.Room' with data contract name 'Room:http://schemas.datacontract.org/2004/07/CommonModel.MODELS' is not expected. Consider using a DataContractResolver or 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.
Can you please help me out how can i use CommonModel classes in WCF service and client (So Room is shared POCO between both the project) and avoid above error?
Thanks
As part of my WCF web service's return message I created three custom classes. They are implemented in my the return message class, which contains a DataContract decoration (pretty sure that's how it's supposed to be done).
However when I run the Visual Studio 2012 WCF Test Client I get the following error message (highlighted in black)
App Code
Class exposed to the program calling the web service. This calls a method with a return type of CloneMessage (detailed below)
namespace OKeeffeDataService
{
public class MonetToDss : IMonetToDss
{
private AgentCloneRules _agentClone;
public MonetToDss()
{
_agentClone = new AgentCloneRules();
}
[PrincipalPermission(SecurityAction.Demand, Role = "AgentPaymentUpdater")]
public CloneMessage CloneRequest(string agentId)
{
//TODO: Validate agent Id?
EventLog.WriteEntry("OKeeffe", "Made it to CloneRequest", EventLogEntryType.Information);
return _agentClone.CloneRequest(agentId);
}
}
}
App Code Interface
namespace OKeeffeDataService
{
[ServiceContract]
public interface IMonetToDss
{
[OperationContract]
CloneMessage CloneRequest(string agentId);
}
}
Clone Message Class
This is the class the WCF service returns. The AgentClone and RelationshipCode classes were generated by the Entity Framework and extend System.Data.Objects.DataClasses.EntityObject. AgentAddresses is a custom class I wrote with standard string properties representing Street, City, State, Zip, etc (listed below).
namespace BusinessEntities
{
[DataContract]
public class CloneMessage : ICloneMessage
{
[DataMember]
public AgentClone AgentInformation { get; set; }
[DataMember]
public IList<AgentAddress> AgentAddresses { get; set; }
[DataMember]
public IList<RelationshipCode> RelationshipCodes { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
public CloneMessage(){}
public CloneMessage(AgentClone agtTran, IList<AgentAddress> addresses, IList<RelationshipCode> relationshipCodes)
{
this.AgentInformation = agtTran;
this.AgentAddresses = addresses;
this.RelationshipCodes = relationshipCodes;
}
}
}
Clone Message Interface
namespace BusinessEntities
{
public interface ICloneMessage
{
AgentClone AgentInformation { get; set; }
IList<AgentAddress> AgentAddresses { get; set; }
IList<RelationshipCode> RelationshipCodes { get; set; }
String ErrorMessage { get; set; }
}
}
EDIT
Adding the enum and classes to the post
AgentAddresses class
AddressType is custom enum.
namespace BusinessEntities
{
[DataContract]
public class AgentAddress : IAgentAddress
{
[DataMember]
public AddressTypeValues.AddressType AddressType { get; set; }
[DataMember]
public string Street1 { get; set; }
[DataMember]
public string Street2 { get; set; }
[DataMember]
public string Street3 { get; set; }
[DataMember]
public string City { get; set; }
[DataMember]
public string State { get; set; }
[DataMember]
public string ZipCode { get; set; }
}
}
AddressTypeValues enum
namespace BusinessEntities
{
public class AddressTypeValues
{
[DataContract(Name = "AddressType")]
public enum AddressType
{
[EnumMember(Value = "Home")]
Home,
[EnumMember(Value = "Mailing")]
Mailing,
[EnumMember(Value = "Location")]
Location,
[EnumMember(Value = "Other")]
Other
}
}
}
AgentClone and RelationshipCode class headers
[EdmEntityTypeAttribute(NamespaceName="AgentResourcesReturn", Name="AgentClone")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class AgentClone : EntityObject
[EdmEntityTypeAttribute(NamespaceName="AgentResourcesReturn", Name="RelationshipCode")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class RelationshipCode : EntityObject
Try adding the following known types to your CloneMessage data contract.
[DataContract]
[KnownType(typeof(AgentClone))]
[KnownType(typeof(AgentAddress))]
[KnownType(typeof(RelationshipCode))]
public class CloneMessage : ICloneMessage
And this AddressTypeValues type to the AgentAddress class.
[DataContract]
[KnownType(typeof(AddressTypeValues))]
public class AgentAddress : IAgentAddress
Once you do this, rebuild the service and try to browse it again the WCF test client.
Add DataContract attribute to AgentClone & RelationshipCode classes
If AddressTypeValues.AddressType is Enum type, then apply the DataContractAttribute attribute to the type. You must then apply the EnumMemberAttribute attribute to each member that must be included in the data contract. refer - http://msdn.microsoft.com/en-us/library/aa347875(v=vs.110).aspx
Add the below attributes to CloneMessage class
[KnownType(typeof(AgentAddress))]
[KnownType(typeof(RelationshipCode))]
try changing like this..
namespace BusinessEntities
{
[DataContract(Name = "AddressType")]
public enum AddressType
{
[EnumMember(Value = "Home")]
Home,
[EnumMember(Value = "Mailing")]
Mailing,
[EnumMember(Value = "Location")]
Location,
[EnumMember(Value = "Other")]
Other
}
}
[DataMember]
public AddressType AddressType { get; set; }
If you are still facing issue, then I am 100% sure that the problem is with AgentInformation/RelationshipCodes. Just comment these two members of CloneMessage class and try. you will get some pointers. If you don't face issue after commenting, then it is something to do with EntityObject. similar issue - Why doesn't WCFTestclient understand standard EF objects but understands STE objects
I'm new to WCF and today I have encountered a problem with DataContracts. I'm getting exception when objects are returned to client from WCF Service.
SvcTraceViewer shows the next exception:
Type
'System.Data.Entity.DynamicProxies.Person_7C797A477DD73534D4E8E743E1FCC1C75DAB75933D03B845A097A8B83F2DD748'
with data contract name
'Person_7C797A477DD73534D4E8E743E1FCC1C75DAB75933D03B845A097A8B83F2DD748:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies'
is not expected. Consider using a DataContractResolver or 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.
I have several projects in solution.
DataAccess (EntityFramework EDMX file is placed here)
Model (Entities generated by DbContextGenerator are here)
WCF Service (DataContracts are implemented in Model project)
WPF Application (runs ServiceHost)
Console Application (calls WCF project or service hosted in WPF Application)
Here is operation contract in WCF:
[OperationContract]
Person[] GetAllPersons(int version);
interface implementation:
public Person[] GetAllPersons(int version)
{
return StorageService.GetAllPersons(version);
}
The excepion is thrown when the data is recieved on the client side (ConsoleApp).
I guess the problem is related to generated entities, because they are partial classes
Here is Person class:
public partial class Person
{
public Person()
{
this.Project = new HashSet<Project>();
}
public int Id { get; set; }
public Nullable<long> AddressId { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public string FirstName { get; set; }
public Nullable<long> GeoLocationId { get; set; }
public string FullGeoLocationName { get; set; }
public Nullable<long> SupervisorId { get; set; }
public Nullable<long> PositionId { get; set; }
public string Position { get; set; }
public string Office { get; set; }
public string NativeName { get; set; }
public string Location { get; set; }
public string FullName { get; set; }
public Nullable<long> PmcPersonId { get; set; }
public virtual ICollection<Project> Project { get; set; }
public virtual PersonDataVersion DataVersion { get; set; }
public virtual Workspace Workspace { get; set; }
}
I tried to mark class and it's members with [DataContract] and [DataMember] attributes, but error still happens. [KnownType(typeof(Person)] attribute also didn't help.
Is it possible to use generated entities as data contracts?
DynamicProxies indicate that you are using lazy loading and the error could be caused by the context being closed when WCF tries to serialize the object.
Try disabling lazy loading and use eager loading instead.
You should really be mapping the Person objects to data transfer objects or Poco objects. You can decorate these properties with DataMember attributes accordingly. If you must disable lazy loading you lose the benefits of the ORM and queries will be run for data you may not even use - may not be a big issue in a small system, but as systems grow it can bring them down to their knees.