svcutil generating MessageContractAttribute or OperationContractAttribute for different services - wcf

I'm using svcutil to make proxy classes and I've noticed that for different services I get different results.
I'm using this svcutil command:
svcutil http://server/SomeService.asmx
/l:c#
/syncOnly
/out:C:\ISomeService
/config:C:\ISomeService.config
/namespace:*,SomeServiceProxy
Proxy classes for first service generate code like this:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="GetFirstService", Namespace="http://othernamespace.com")]
public partial class GetFirstServiceRequest : SomeServiceProxy.ResponseInfoBase
{
...
}
And proxy classes for second service generate this:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
[System.ServiceModel.MessageContractAttribute(WrapperName = "GetSecondService", WrapperNamespace = "http://somenamespace.com", IsWrapped = true)]
public partial class GetSecondServiceRequest
{
...
}
Why is one class marked with MessageContractAttribute and the other with DataContractAttribute? How does svcutil decide to use one or the other, the command is same for both services?

The DataContract format supports only a subset of XML Schema Definition. So it depends on the service metadata: svcutil (actually System.ServiceModel.Description.WsdlImporter which is used by svcutil) tries to generate DataContracts by default. If it encounters a schema that cannot be represented as a DataContract, it generates a MessageContract as fallback.

Related

DataContractException in hosted WCF service

I am trying a host a service where there is a method that returns the following type:
[DataContract]
[Obfuscation(ApplyToMembers = true, Exclude = true)]
[Serializable]
public class Output
{
[DataMember]
public DataSet dsOutput{get;set;}
}
The method signature is as follows:
[OperationContract]
[WebGet]
function Output matchData(DataSet pDSSide1,DataSet pDSSide2)
{
return new Output();
}
On browsing the service I encounter the following exception:
System.InvalidOperationException: An exception was thrown in a call to a WSDL export extension:System.ServiceModel.Description.DataContractSerializerOperationBehavior
contract: http://tempuri.org/:TesterTool ---->
System.Runtime.Serialization.InvalidDataContractException: Type 'System.Data.DataRow' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
`
Any suggestions.
It's not a good practice to send a DataTable over a service.
As stated by govindaraj here:
The best way is to use custom collection of custom object.
If you're using 2.0, then you can use generic collection instead of
custom collection to reduce code.
How?
Create a custom data object (containing only private fields and public properties for each field) that is similar to each row in the
datatable.
Create a layer that will do all database (in this case, dataset) access and translation to the custom object.
All client code will access that layer.

WCF DataContract centralization

I have several WCF services that use the same dataContracts to interchange data between them.
Can I have a sort of Metadata Endpoint for centralizing the management of all this schemas?
When creating a new WCF service, how can i make it to load the schemas from the Metadata Endpoint (instead of redefining them) to use inside its operationContracts?
Thanks!
As I said in the comment, I'm not sure I understand your question (at least with regards to wanting a metadata endpoint), but it sounds like you want to have the ability to reuse existing data contracts in multiple different services.
The easiest way to do that is to put the data contracts in a separate assembly (class library - DLL), and then have the services reference that assembly - they don't have to be defined inside the service itself.
Here's a trivial example (code is for illustration only, not intended to actually do anything or be a complete sample):
MyDataContracts assembly
namespace MyDataContracts
{
[DataContract]
public class DataContract1
{
}
[DataContract]
public class DataContract2
{
}
}
MyService1 assembly
using MyDataContracts;
namespace MyService1
{
[ServiceContract]
public interface IMyService1
{
[OperationContract]
DataContract1 GetSomeData(string someParm);
}
}
MyService2 assembly
using MyDataContracts;
namespace MyService2
{
[ServiceContract]
public interface IMyService2
{
[OperationContract]
void SendSomeData(DataContract1 dc);
[OperationContract]
DataContract2 GetSomeOtherData(int parm);
}
}
Of course, each of the WCF service projects will need to include a reference to the MyDataContracts assembly as well.
Now whenever you create a new service, you simply add a reference to the MyDataContracts.dll and you can reuse your data contracts in it.

WCF and Castle library (Glass Mapper)

hello I have WCF service with webHttpEndpointBehavior under Sitecore 6 and I use Glass Mapper to read items, Glass mapper has depends on Castle library.
It is working well, but i have some methods with Contract like:
[OperationContract]
[WebInvoke(Method = "POST",BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
List<Shade> GetAllShades(int columns, int rows);
where I try return list of my class in JSON format,
during debug my service with SvcTraceViewer.exe I find out next error:
There was an error while trying to serialize parameter
:GetFamilyShadesResult. The InnerException message was 'Type
'Castle.Proxies.ShadeProxy' with data contract name
'ShadeProxy:http://schemas.datacontract.org/2004/07/Castle.Proxies' 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.
How to resole this issue? Castle.Proxies.ShadeProxy is a dynamic class under Castle and I can't use KnownTypeAttribute.
Actually if I JSON.net library and return results as string everything works fine.
I assume you have a class that links to other classes loaded via Glass, e.g.
[SitecoreClass]
public class Shade{
[SitecoreField]
public virtual IEnumerable<AnotherClass> SomeField{get;set;}
[SitecoreChildren]
public virtual IEnumerable<AnotherClass> Children{get;set;}
}
[SitecoreClass]
public class AnotherClass{}
To allow lazy loading of classes Glass uses proxies generated by Castle, so at runtime when the classes are loaded into the SomeField property you actually get a sub-class of the AnotherClass class.
To resolve this you have to explicitly tell class to load the other classes as concrete types, updating the SitecoreField attribute should fix this problem:
[SitecoreClass]
public class Shade{
[SitecoreField(Setting=SitecoreFieldSettings.DontLazyLoad)]
public virtual IEnumerable<AnotherClass> SomeField{get;set;}
[SitecoreChildren(IsLazy=false)]
public virtual IEnumerable<AnotherClass> Children{get;set;}
}
[SitecoreClass]
public class AnotherClass{}

trying to expose my Service layer as WCF

I have my service layer, entities and DTOS in a separeted assembly called CCL.Data
The problem:
All My application is referencing the service layer directly using interfaces and IoC.
For example, I have an interface in my CCL.Data assembly called ICustomerService it depends on ICustomerRepository that depends on MyContext. All my application is referencing ICustomerService to call its methods....... so far no problem.
So I created a WCF Project.... referencing CCL.Data in this project....
I create a new Service, but int this case below, I would need to change all points in my application that call ICustomerService to WCFCustomerServiceClient, does exists a better way without cause a big impact in my project?
[ServiceContract]
public interface IWCFCustomerService
{
[OperationContract]
CustomerDTO GetCustomerById(int id);
}
public class WCFCustomerService : IWCFCustomerService
{
ICustomerService _customerService;
public WCFCustomerService()
{
MyContext context = new MyContext();
ICustomerRepository customerRep = new CustomerRepository(context);
_customerService = new CustomerService(customerRep);
}
public CustomerDTO GetCustomerById(int id)
{
return _customerService.GetCustomerById(id);
}
}
Tks,
William
Do you need to redefine IWCFCustomerService in place of ICustomerService? Is it not possible just to add ServiceContract attributes to your original ICustomerService interface (they will just get ignored by non WCF code)? (Its true that this does give you a dependancy on ServiceModel - but I cant see a way out of that).
Note also that if you use a ServiceRefernce to generate proxy code then the code generated will include a your service interface in different namespace for use clientside. Its worth noting that your not abliged to use that version of the interface (which could be annoying if you have a proxy and not proxy implimentation) but can still use the org interface definition either from a dll or compiled into your client.

Do WCF and DataContractSerializer serialize CollectionDataContract-decorated collection types differently?

I have a really simple customized collection type that inherits from List<> and uses a CollectionDataContract.
When I use DataContractSerializer.WriteObject to serialize it, it respects the CollectionDataContract attribute the way I'd expect; however, when I use it as a return type for a WCF method, I get the default ArrayOfFoo.
I'm wondering if there is some decoration I'm missing in the service contract.
Details:
[DataContract(Namespace = "")]
public class Foo
{
[DataMember]
public string BarString { get; set; }
}
[CollectionDataContract(Namespace = "")]
[Serializable]
public class FooList : List<Foo> {}
If I just instantiate a Foo and then use DataContractSerializer.WriteObject to serialize it, I get what you'd expect:
<FooList>
<Foo>
<BarString>myString1</BarString>
</Foo>
</FooList>
However, if I have a service with a method like this...
[ServiceContract Name = "MyService"]
public interface IMyService
{
[OperationContract, WebGet(UriTemplate = "foos/")]
FooList GetAllFoos();
}
and then do a GET for http://www.someEndpoint.com/foos/, I get this:
<ArrayOfFoo>
<Foo>
<BarString>myString1</BarString>
</Foo>
</ArrayOfFoo>
I've also tried specifying Name="MyFooListName" in the CollectionDataContract attribute. Same results: DataContractSerializer gets the memo; WCF doesn't.
Saeed sent me in the right direction: I inadvertently ended up with XmlSerializer, when I had been hoping for DataContractSerializer.
I had ended up with XmlSerializer... well... by asking for it.
In particular, I had decorated methods in my service with the XmlSerializerFormat like this:
[ServiceContract Name = "MyService"]
public interface IMyService
{
// ... other stuff ...
[OperationContract, WebInvoke(UriTemplate = "foos/", Method = "POST")]
[XmlSerializerFormat]
Foo PostAFoo(Foo yourNewFoo);
}
I had done this in the hopes of forgiving member order in hand-rolled Foo XML blobs. Of course, when one does this one ends up with XmlSerializer, not DataContractSerializer.
When I take away the XmlSerializerFormat attribute, problem solved: WCF is now serializing my FooList collection the way I want.
See MSDN for detail:
The DataContractSerializer does not
support the programming model used by
the XmlSerializer and ASP.NET Web
services. In particular, it does not
support attributes like
XmlElementAttribute and
XmlAttributeAttribute. To enable
support for this programming model,
WCF must be switched to use the
XmlSerializer instead of the
DataContractSerializer.
So the serialization going to be done by XMLSerializer, and you can't change it.
Have you selected Generic types while configuring your WCF service? if not then,
right click and go to configuration, then select Generic Type, by default it is arraylist type.