Can i use datacontracts in WCF for streaming - wcf

Please can i use datacontracts in WCF for streaming instead of message Contract.
If yes, will it offer any performance improvement?
THanks

Answer depends on binding you use. For TCP or Named pipe transport protocols you can stream any data - including data contracts. If you want to use streaming over HTTP (supported by BasicHttpBinding) you have to some several constraints:
Streaming has to be allowed on binding
Operation has to work with Stream instance or Message contract which contains only single body element of type Stream. Data contracts are allowed only as custom message headers on Message contract.
Only valid operation definitions for streaming over HTTP are:
// StreamedResponse
[OperationContract]
Stream GetData(int id);
// StreamedRequest
[OperationContract]
int PostData(Stream data);
// Streamed
[OperationContract]
Stream WorkWithData(Stream data);
[OperationContract]
DoSomethingResponse DoSomething(DoSomethingReqest request);
[MessageContract]
public class DoSomethingRequest
{
// Custom data and data contract allowed only as SOAP headers which are always buffered
[MessageHeader]
public MyDataContract CustomHeader { get; set; }
// No other member allowed
[MessageBodyMember]
public Stream Data { get; set; }
}
[MessageContract]
public class DoSomethingResponse
{ ... }
If you don't follow these constraints you will end up with two cases:
Operation is not streamed even if you configure binding for streaming - this happens if you don't use Stream instance as message content
Exception - this happens if you use Stream instance + other data / data contract as message content

Related

Syncing correlationstate between IClientMessageInspector and IParameterInspector

I have a wcf client. According to requirements, I need to record some of the metadata in the request (as well as user data which is not included in the request.) Then, if the request is successful I may have to record response metadata and depending on flags, the full soap request.
I am trying to do this the right way (using IParameterInspector to examine the metadata and IClientMessageInspector to get the Soap), but I have no way of correlating the two Interface requests. I am not sure about thread safety here. This is a stripped down version of where I am at...
public class SoapRequestInfo
{
public string UserId { get; set; }
public Guid Key { get; set; }
//would contain a lot more info
}
public class OperationProfilerParameterInspector : IParameterInspector, IClientMessageInspector
{
//before serialization
public object BeforeCall(string operationName, object[] inputs) //IParameterInspector
{
//Add the operation, record some specific inputs to db
return new SoapRequestInfo
{
UserId = "1234",
Key = new Guid()
};
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) //IParameterInspector
{
var info = correlationState as SoapRequestInfo;
//Do some additional logging - easy enough
}
public object BeforeSendRequest(ref Message request, IClientChannel channel) //IClientMessageInspector
{
//want to correlate this with IParameterInspector
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState) //IClientMessageInspector
{
//May want to log full soap message depending on after call criteria
}
}
I know I can't use a private variable to hold the Guid. I can't use session, because there can be multiple requests in close succession and can't guarantee the response is correct. So how can I uniquely identify the correlationState between the two interfaces?
You can probably use HttpContext.Items to keep your object if your service is running in ASPNET compatibility mode otherwise you can use TLS (Thread Local Storage), put the data in a slot and fetch/clear later.
May eb you can tro to do this little bit diffrent:
From this post passing correlation token to WCF service?:
If you use message version with WS-Addressing you should have it automatically because each messages will contain its autogenerated ID (guid) and each response will contain ID of the request as well. You can access these headers through OperationContext
If using messages is not fit your requirements, probably you can try to put your own id in the header when you send request, and probably update the response with same id.

Roundtripping DataContracts andDenial Of Service attacks

I am working on a datacontract as follows that uses IExtensiblesDataObject to make it forward compatible with version 02 of this contract, but am worried about possible 'accidental' denial of service via clients passing excessive quantities of data over the wire that needs to be de-serialised, re-serialised and sent back.
Without turning the support off via the ignoreExtensionDataObject in the config file, is there a way of protecting against such an eventuality, i.e. can you cap the quantity somehow ?
[DataContract(Namespace="http://schemas.myComany.com/sample/01")]
public class Sample : IExtensibleDataObject
{
[DataMember]
public int32 sample_ID;
private ExtensionDataObject _data;
public virtual ExtensionDataObject ExtensionData
{
get { return _data; }
set { _data = value; }
}
....
}
Thanks in advance
The way to protect your service is limiting MaxReceivedMessageSize (by default it is 65KB) and reader quotas in your binding.

WCF Msmq problem reading messages using netMsmqBinding

I have a WCF service using netMsmqBinding that I am using to add messages of Msmq<string> to a queue. The messages are added fine and I can see them in the queue via the computer management console.
I have another WCF service that is trying to retrieve the messages from the queue, this is where I'm having a problem. My method in my service is getting called whenever a message is added to the queue (that bit is working fine) but the Msmq<string> message seems to have all null values.
I'm not sure how I can get the message from that Msmq<string>? Here is my service details... any help appreciated..
[ServiceContract]
[ServiceKnownType(typeof(Msmq<string>))]
public interface IMessageListener
{
[OperationContract(IsOneWay = true, Action = "*")]
void ListenForMessage(Msmq<string> msg);
}
public class MessageListener : IMessageListener
{
[OperationBehavior(TransactionScopeRequired = false, TransactionAutoComplete = true)]
public void ListenForMessage(MsmqMessage<string> msg)
{
//this gets called and seems to remove the message from the queue, but message attributes are all null
}
}
I think you're not quite "getting" the idea of WCF over MSMQ.
When using WCF with the netMsmqBinding, the whole idea is that you don't need to deal with the details of MSMQ - let the WCF runtime handle that!
So basically, your approach should be as with any WCF service:
define your service contract and its methods (operation contract)
define your data structures as a [DataContract] and use those in your service methods
implement the service
So your service should be something like:
[DataContract]
public class Customer
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
...
}
[ServiceContract]
public interface ICustomerService
{
[OperationContract(IsOneWay=true)]
void SaveCustomer(Customer myCustomer)
[OperationContract(IsOneWay=true)]
void CreateCustomer(int ID, string name);
}
You should have a data contract to describe your data - just your data, no MSMQ details needed here! Then you should have one set of service methods that will deal with the Customer object - you can put it into the queue for storing, create a new one etc.
You would then implement the client and the server side for this service contract, and the WCF runtime will handle all the details of MSMQ transport, putting the payload (the Customer object) into a MSMQ message and getting it back out again and so on... you don't have to deal with that, really.

WCF Additional Proxy Classes

I have a WCF webservice that has the following service contract
[ServiceContract(Namespace = "http://example.org")]
public interface IEquinoxWebservice
{
[OperationContract]
Guid Init();
[OperationContract]
List<Message> Dequeue(Guid instanceId);
[OperationContract]
void Enqueue(Guid instanceId, Message message);
[OperationContract]
void Dispose(string instanceId);
}
Message class is an abstract class that is implemented by a bunch of concrete message classes.
I want to make all the concrete message classes available in the client proxy that is generated. Not just the message class.
Is there any way to make them available as types in the webservice so the standard Visual Studio proxy generator will create them?
You need to specify those types. See Data Contract Known Types.

RESTful WCF service that can respond in both JSON(P) and XML and still be used as SOAP web service?

Given a contract such as:
[ServiceContract] public interface IService
{
[OperationContract]
[WebGet(UriTemplate = "GetData/{id}.{format}")]
ResponseData GetData(string id, string format);
}
Is there a way to get the service to respond with json when requested as:
/GetData/1234.json, xml when requested as /GetData/1234.xml and still be available as a proper soap service at some other url, with a strongly typed wsdl contract?
Using a Stream as the return value for GetData is not workable, as though it fufills the first two requirements, wcf can't create a full wsdl specification as it has no idea what the contents of the resultant Stream will be.
You should have two separate methods which take id and format (and they would call a shared implementation that returns ResponseData) which have different WebGet attributes:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebGet(UriTemplate = "GetData/{id}.{format}.xml",
ResponseFormat=WebMessageFormat.Xml)]
ResponseData GetDataXml(string id, string format);
[OperationContract]
[WebGet(UriTemplate = "GetData/{id}.{format}.json",
ResponseFormat=WebMessageFormat.Json)]
ResponseData GetDataJson(string id, string format);
}
For the SOAP endpoint, you should be able to call either method, but you are going to have to have a separate ServiceHost instance hosting the implementation of the contract.