Adding field to WCF data contract breaks clients? - wcf

I have a WCF service that returns a class that implements IExtensibleDataObject. I need to add a new field to this class. I updated the DataContract interface and made the change to the class. Now when I try to run my client application I get the following error:
Could not load file or assembly
'xxx.yyyy.zzzz, Version=1.3.9.26111,
Culture=neutral,
PublicKeyToken=b09e2f3e9b5894f0' or
one of its dependencies. The located
assembly's manifest definition does
not match the assembly reference.
(Exception from HRESULT: 0x80131040)
The AssemblyVersion of the WFC class has been changed - does that break client?
EDIT:
There are clients in production that use this service. I do not want to make them update their service reference and redeploy their clients for this simple change if possible.

It depends on how you have set up your data contract.
In WCF, using all the defaults, your service will use the DataContractSerializer (DCS) to serialize your object into XML. The DCS will serialize your fields in order - first the public ones, then the private ones. Within each visibility group, it will order the fields/properties alphabetically by name.
Thus, if you introduce a new public property MiddleName and you already had FirstName and LastName, you would be fine: the old XML would have been
<YourObject>
....
<FirstName>.....</FirstName>
<LastName>.....</LastName>
</YourObject>
and your new one would just simply add a new property at the end:
<YourObject>
....
<FirstName>.....</FirstName>
<LastName>.....</LastName>
<MiddleName>....</MiddleName>
</YourObject>
Such an update "add something at the end" should work just fine, the DCS will just simply ignore additional tags in the XML.
However: had you introduced a property called Gender, that would be stuck between <FirstName> and <LastName> and would thus break the order of the data in your XML and thus would break the data contract - no "old" client will be able to call your new service.
In order to take control of this, you can put specific Order= attributes on your data members in your data contract:
[DataContract]
public class SomeAddress
{
[DataMember(Order=0)]
public string FirstName;
[DataMember(Order=1)]
public string LastName;
}
Then you could easily add a new property - just add it to the end of the list!
[DataContract]
public class SomeAddress
{
[DataMember(Order=0)]
public string FirstName;
[DataMember(Order=1)]
public string LastName;
[DataMember(Order=2)]
public string Gender;
}
So by using the Order= attribute on your data contracts, you can take control of your XML layout, and you can make simple extensions of existing data contracts non-breaking updates.
For more background and in-depth know-how, you ought to read Serialization in Windows Communication Foundation on MSDN Magazine's web site - highly recommended.

From your service reference context menu choose... "Update Service Reference"

Related

Can I reference a DataContract and its proxy version from same class

I'm dipping my foot into WCF and am trying to make a simple test project that can both consume the service as a service and also directly instantiate it's classes and work with them.
I had an earlier working version where data passed was just primitive types. However, when I attempted to convert to using data contracts, I'm getting conflicts in whether it's referencing the proxy-declared version of the contract or the version from the project itself.
Question: Is it possible to do this and if so, how would I resolve the data contract references?
private void Test()
{
MyService fssDirect = new MyService(); // direct instantiation
MyServiceClient fssService = new MyServiceClient(); // Service proxy
ClientCredentialsContract Client = new ClientCredentialsContract();
ResponseDataContract Result = new ResponseDataContract();
if (CallAsService)
{
Result = fssService.Create(Client, Request);
}
else
{
Result = fssDirect.Create(Client, Request);
}
}
In the above, any reference to the RequestDataContract and ClientCredentialsContract types indicates
Warning: The type 'MyContracts.RequestDataContract' in 'C:...\Test\MyServiceProxy.cs' conflicts with the imported type 'MyContracts.RequestDataContract' in 'C:...\MyService\bin\Debug\Contracts.dll'. Using the type defined in 'C:...\Test\MyServiceProxy.cs'.
(Names changed and paths shortened to protect the innocent)
Thanks,
John
When you create the proxy for your service, try referencing the assembly which contains the data contracts (if using "Add Service Reference", go to the advanced options, select "reuse types in referenced assemblies"; if using svcutil, use the /r argument). This way the tool won't generate the data contracts and you won't have the conflicts.

WCF service with 4 input parms and 3 out parms gets reordered by Add Service Reference in Proxy Class Project

I've looked in SO and elsewhere and seen questions posed about this along with some answers that still make no sense to me in my case.
I'm refactoring my working VStudio 2010 solution which has:
one project with an ASMX webservice
another separate project for the proxy class (no code here except what is generated by Add Web Reference
another separate project for the client (contains a reference to the
ProxyClass.dll
The new VStudio 2010 solution has:
one project of type WCF service library for the contract by itself (IFileService.cs)
one project of type WCF service library for the implementation of the contract (FileService.cs)
another separate project for the proxy class (no code here except what is generated by Add Service Reference
another separate project for the client (contains a reference to the WCFProxyClass.dll)
Here is the contract which ends with 3 out parameters (and the implementation of same is the same order):
[ServiceContract(Name = "IFileService", Namespace = "http://www.cbmiweb.com/TrimWCF/2011/11")]
public interface IFileService
{
[OperationContract]
public string DownloadFile(string trimURL
, string TrimRecordNumber
, string CallerPC
, string RequestorID
, out byte[] docContents
, out string returnFiletype
, out string returnFilename)
{
Here is what Add Service Reference generated in my proxy class project:
public string DownloadFile(
out byte[] docContents
, out string returnFiletype
, out string returnFilename
, string trimURL
, string TrimRecordNumber
, string CallerPC
, string RequestorID)
{
return base.Channel.DownloadFile(out docContents, out returnFiletype, out returnFilename, trimURL, TrimRecordNumber, CallerPC, RequestorID);
}
I have read answers ranging from "you cannot use out parms in WCF" to "you should not use Add Service Reference but instead use svcutil.exe" to "the order of the parameters do not matter...it will still work".
I am confused about what to do here (and what I've done wrong that led to this re-arranged order and WHY that happened).
First of all, you haven't done anything wrong :). Even though the signatures in the methods in the client and the server are different, they're equivalent wrt the messages which will be produced / consumed by them. You can use that proxy class without any problems, and it should work just as well.
Why this happens is another story - in the service description (WSDL), there are two "messages" for each (non-one-way) operation: one with the input parameters, one with the output parameters. The messages contains respectively the input(s) and output(s) of the operation, but there's nothing in the WSDL which shows the order of them. So when a tool such as Add Service Reference or svcutil is generating the client proxy, it will simply "choose" one order (out parameters first), but the request which the proxy will send to the service will be compatible with what the server expects (and also, the response from the server will be correctly understood by the proxy).
If you want to maintain the order of the parameters, you can create the proxy class yourself. For this you can either use the ChannelFactory<T> class, or create your own client class derived from ChannelBase<T>. But you don't really need to do that, as I mentioned before.

WCF Data Services error "The given name 'Foo' was not found in the entity sets"

I'm developing a WCF Data Service to expose a database. I want to provide access to one of the tables (call it 'Foo'), so I put this in the InitializeService method of my DatabaseService.svc.cs:
config.SetEntitySetAccessRule("Foo", EntitySetRights.AllRead);
However, when the service is initialized it throws an ArgumentException with the message "The given name 'Foo' was not found in the entity sets."
The table is definitely in the .edmx file with that name, case and spelling correct. It's also in the .Designer.cs file, like this:
[EdmEntityTypeAttribute(NamespaceName="FooDBModel", Name="Foo")]
[Serializable()]
[DataContractAttribute(IsReference=true)]
public partial class Foo : EntityObject
The service class itself is declared as:
public class FooDatabaseService : DataService<FooDBEntities>
Have you tried using the fully qualified name?

Consume WCF Data service in client application throws error

I am working on WCF Data service which imported stored procedure, as below.
[WebGet]
public List<GetMTSearchResultTest_Result> GettMTSearchResultTest()
{
MediaMarketResearch_PRODEntities ent = new MediaMarketResearch_PRODEntities();
return ent.GetMTSearchResultTest().ToList();
}
when i consuming this in my client application it says error as "The closed type MMRClient.MMRServiceReference.GetMTSearchResultTest_Result does not have a corresponding element settable property."
I am getting this error while bind to the grid view as below.
DataServiceContext context = new DataServiceContext(new Uri("http://localhost:4131/MMRDataService.svc/"));
IEnumerable<GetMTSearchResultTest_Result> empResult = context.Execute<GetMTSearchResultTest_Result>(new Uri("http://localhost:4131/MMRDataService.svc/GettMTSearchResultTest"));
GridView1.DataSource = empResult;
GridView1.DataBind();
Note: I imported this stored proc as complex type.
Please advice me on this.
Regards,
Jaydeep
I think this link may help you (see the selected answer).
Essentially, what the solution may be is to create a partial class for GetMTSearchResultTest_Result and decorate it with a DataServiceKey attribute, providing a non-nullable column that acts as a primary key (although I don't think it has to be unique).
So your partial class would look something like:
[DataServiceKey("YourKeyColumnName")]
public partial class GetMTSearchResultTest_Result {
}
If you're just doing reads, I don't think you'll need any implementation.
Hopefully this works. Let me know if there are issues/questions and I'll update accordingly.
You can always make a new service reference to a non data service. That is to a normal WCF service. You can simply have a [ContractOperation] returning a list of the troubled "complex types" and that's it.
This way you would have two services the original data service and a new normal WCF service. But this shouldn't be such an issue. You don't have to make the troubled "complex type" as a Entity.

Showing enums client side from wcf service

I don’t know if it’s possible, but I want to be able to refer to enums from my WCF service on the client side. I have one core project, and in that project the enums are:
public enum StatusType
{
Ok = 1,
Error = 2,
Unknown = 0
}
public enum DirectionType
{
None = 0,
ToSystem = 1,
FromSystem = 2
}
I have one Service project using the core project and it is setting the enum types from the core project likes this:
[DataContract()]
static class EnumHelper
{
public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
{
List<Type> knownTypes = new List<Type>();
// Add any types to include here.
knownTypes.Add(typeof(StatusType));
knownTypes.Add(typeof(DirectionType));
return knownTypes;
}
}
And in the interface :
[ServiceKnownType( typeof(EnumHelper))]
[ServiceContract( SessionMode = SessionMode.Allowed)]
public interface HandlerService
when I call a method either who takes or returns an enum, it works fine, but I then have to refer to the core project in the client project to use the enums client side, I would want to do that from the Service if it’s possible.
I have tried to set the enums in the core project to
[DataContract]
public enum StatusType
{
[EnumMember]
Ok = 1, /*!<Done with no error */
[EnumMember]
Error = 2, /*!<Done with error */
[EnumMember]
Unknown = 0, /*!<No data registered, default value */
}
with no effect.
I want to use it like this in my client project:
Either like client.StatusType.Ok or Servicereference1.StatusType.Ok or something like that,
note like Core.StatusType.Ok
The reason I want this, is because the Service should be used in different projects, and we don’t want everyone to be dependent on a common dll liberary, if it’s possible to skip it. I use net.tcp binding for the service. Hope it was understandable, thanks for any help :)
If you want to share types and classes between server and client, you have to put them into a separate assembly, and use that on both the server and the client side. This only works if you control both ends of the wire, e.g. write both the server and the client side of the code (which I believe you are).
If you create a separate MyWCFTypes assembly on the server side, you can reference that assembly in your client projects as well, and when importing the service definition, WCF should reuse existing classes, e.g. should reuse your MyWCFTypes classes without creating new classes for the same enums.