Setting Message version in code for WCF client - wcf

I want to set message version for WSHttpBinding to EnvelopeVersion.Soap11. I don't know how to do that. Can any one help me. Here is my binding code
var binding = new WSHttpBinding()
{
UseDefaultWebProxy = true,
Security =
{
Mode = SecurityMode.Transport,
Transport =
{
ClientCredentialType = HttpClientCredentialType.Basic
},
},
};
EDIT:
here is the code to do that
TransportBindingElement transportElement = null;
transportElement = new HttpsTransportBindingElement();
((HttpsTransportBindingElement)transportElement).AuthenticationScheme = AuthenticationSchemes.Basic;
((HttpsTransportBindingElement) transportElement).KeepAliveEnabled = false;
var messegeElement = new TextMessageEncodingBindingElement
{
MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap11, AddressingVersion.None),
ReaderQuotas =
{
MaxArrayLength = 200000,
MaxBytesPerRead = 200000,
MaxDepth = 200000,
MaxNameTableCharCount = 200000,
MaxStringContentLength = 200000
}
};
var binding = new CustomBinding(messegeElement, transportElement);
return binding;

In order to achieve this, you need to define a custom binding - in config or in code.
In config, you'd do it something like this:
<system.serviceModel>
<bindings>
<customBinding>
<binding name="Soap11">
<textMessageEncoding messageVersion="Soap11" />
<httpTransport />
</binding>
</customBinding>
</bindings>
and then, in your service or client config, use something like this:
<services>
<service name="test">
<endpoint name="TestEP"
address=""
binding="customBinding"
bindingConfiguration="Soap11"
contract="IService" />
</service>
</services>
</system.serviceModel>

Related

WCF Timeout exception on streaming big files

I'm currently working on a WCF streaming service. So far everything works great for files up to 2 GB. I've set up the service as a streaming service and I am chunking the files on my own on 5 MB chunks. However, files bigger than 2 GB (somewhere there is the threshold) i always get an InvalidOperationExceptionwith the message Timeouts are not supported on this stream. I'm not really sure why and where this exception is thrown. It don't think this is a server side problem because every request should be the same and most of them work. But the exceptions comes from the generated proxy. So the source is System.Private.ServiceModel
Stack trace:
at System.Runtime.AsyncResult.End[TAsyncResult](IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
at System.ServiceModel.Channels.ServiceChannelProxy.TaskCreator.<>c__DisplayClass0.<CreateGenericTask>b__1(IAsyncResult asyncResult)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Company.OurApp.App.DataService.BaseFile.<DownloadItem>d__59.MoveNext()
Here is my server implementaion:
var response = new GetFileResponse();
using (var impersonation = new Impersonation(request.Domain, request.Username, request.Password))
{
using (Stream fStream = File.OpenRead(request.FullFilePath))
{
fStream.Seek(request.FilePart * request.FilePartSize, SeekOrigin.Begin);
BinaryReader bStream = new BinaryReader(fStream);
var filePart = bStream.ReadBytes(request.FilePartSize);
using (Stream mStream = new MemoryStream(filePart))
{
response.FileByteStream = mStream;
return response;
}
}
}
The GetFileResponse looks like this:
[MessageContract]
public class GetFileResponse
{
[MessageBodyMember(Order = 1)]
public Stream FileByteStream { get; set; }
}
This is how the client handles the download (UWP App):
using (Stream f = await StorageFile.OpenStreamForWriteAsync())
{
//Cancelation area - after every async operation if possilble
for (int i = 0; i < sections; i++)
{
token.ThrowIfCancellationRequested();
var response = await client.GetFilePartAsync(request.ConnectionPassword, request.Domain, i, FilePartSize, FullPath, request.Password, request.Username);
token.ThrowIfCancellationRequested();
DownloadProgress = response.FileByteStream.Length;
f.Seek(0, SeekOrigin.End);
await f.WriteAsync(response.FileByteStream, 0, response.FileByteStream.Length);
await f.FlushAsync();
}
}
And here is the service web.config:
<system.serviceModel>
<services>
<service behaviorConfiguration="HttpsServiceBehaviour"
name="Company.OurApp.TransportService.DataService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="streamedBinding" contract="Company.OurAppTransportService.IDataService">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="HttpsServiceBehaviour">
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="streamedBinding" transferMode="Streamed" closeTimeout="10:00:00">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
When generating the client proxy, i set some timeouts but that didn't change anything:
public DataServiceClient GetDataServiceClient(string endpoint = null)
{
var useEndpoint = String.IsNullOrEmpty(endpoint) ? Configuration.ConfigService : endpoint;
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.MaxBufferSize = int.MaxValue;
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
result.MaxReceivedMessageSize = int.MaxValue;
result.AllowCookies = true;
result.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;
//TODO Try to work with timeouts for larges files?
result.SendTimeout = TimeSpan.FromMinutes(5);
result.ReceiveTimeout = TimeSpan.FromMinutes(5);
result.OpenTimeout = TimeSpan.MaxValue;
if (useEndpoint.ToLower().StartsWith("https://"))
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
else
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.TransportCredentialOnly;
var client = new DataServiceClient(result, new System.ServiceModel.EndpointAddress(String.Concat(useEndpoint, fixedEndpointSuffix)));
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
if (AppState.IsLoggedIn)
{
client.ClientCredentials.Windows.ClientCredential.UserName = $#"{AppState.Domain}\{AppState.User}";
client.ClientCredentials.Windows.ClientCredential.Password = AppState.Password;
}
return client;
}
Any idea where and why the exception is thrown? Server? Client? Is it coming from the stream? Help is very much appreciated.
For everybody else facing the same problem. I got it solved by analyzing the exceptions with the WCF TraceViewer. I also called the Service from a console application to be sure it's not a UWP problem. The problem was that I closed the streams before the response could reach the client.
Broken implementation:
var response = new GetFileResponse();
using (var impersonation = new Impersonation(request.Domain, request.Username, request.Password))
{
using (Stream fStream = File.OpenRead(request.FullFilePath))
{
fStream.Seek(request.FilePart * request.FilePartSize, SeekOrigin.Begin);
BinaryReader bStream = new BinaryReader(fStream);
var filePart = bStream.ReadBytes(request.FilePartSize);
using (Stream mStream = new MemoryStream(filePart))
{
response.FileByteStream = mStream;
return response;
}
}
}
This one fixed it for me:
Stream fStream = File.OpenRead(request.FullFilePath);
long offset = request.FilePart * request.FilePartSize;
fStream.Seek(offset, SeekOrigin.Begin);
BinaryReader bStream = new BinaryReader(fStream);
var filePart = bStream.ReadBytes((int)request.FilePartSize);
Stream mStream = new MemoryStream(filePart);
response.FileByteStream = mStream;
return response;
Hope it helps!

WCF XML & JSON support using a single OperationContract method?

I was trying to work on the following requirement for days. I would like my WCF API to handle XML and JSON requests/responses using a single method. I also know that .net 4 supports automaticformat selection but it does not work the way i want my XML & JSON structures to be. Here are my structures:
JSON:
{
"response": {
"timestamp": "12.00AM",
"locations": {
"location": [
{
"id": "5",
"name": "hello world",
"statusid": "8"
}
]
},
"errorcode": "444"
}
}
XML:
<response>
<timestamp>12.00AM</timestamp>
<locations>
<location>
<id>5</id>
<name>hello world</name>
<statusid>8</statusid>
</location>
</locations>
<errorcode>444</errorcode>
</response>
I have tried toggling the value of "BodyStyle" in my OperationContract, e.g. for JSON i have to put WebMessageBodyStyle.Wrapped and for XML i have to put WebMessageBodyStyle.Bare to work according to the above structures. Since i want to be able to use one OperationContract and automatically respond with XML/JSON structures depending on the Content-Type, what changes/additions do i have to make? Is there a way to set this BodyStyle using Code for both XML and JSON (P.S. API should be the way it is and should not be able pass any parameters like getvalue/{xml})?
Thank you in advance.
UPDATE: below is my OperationContract:
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "PushNotify")]
ResponsePushNotify PushNotify(RequestPushNotifiy pushnotify);
Here is the DataContract:
[DataContract]
public class Test: ITest
{
responsePushNotify = new ResponsePushNotify();
ResponsePushNotify PushNotify(RequestPushNotifiy pushnotify)
{
if (Content-Type == "application/json; charset=utf-8")
{
OperationContext.Current.OutgoingMessageProperties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json));
}
responsePushNotify.id = "1";
responsePushNotify.value = "Hello World";
return responsePushNotify ;
}
Here's the suggested code:
public class MyWebHttpBehavior : WebHttpBehavior
{
protected override IDispatchMessageFormatter GetReplyDispatchFormatter(OperationDescription operationDescription, ServiceEndpoint endpoint)
{
WebGetAttribute webGet = operationDescription.Behaviors.Find<WebGetAttribute>();
IDispatchMessageFormatter json = null, xml = null;
WebMessageFormat originalFormat = webGet.ResponseFormat;
webGet.ResponseFormat = WebMessageFormat.Json;
json = base.GetReplyDispatchFormatter(operationDescription, endpoint);
webGet.ResponseFormat = WebMessageFormat.Xml;
xml = base.GetReplyDispatchFormatter(operationDescription, endpoint);
webGet.ResponseFormat = originalFormat;
return new MyReplyDispatchMessageFormatter(json, xml);
}
}
public class MyReplyDispatchMessageFormatter : IDispatchMessageFormatter
{
IDispatchMessageFormatter jsonFormatter;
IDispatchMessageFormatter xmlFormatter;
public MyReplyDispatchMessageFormatter(IDispatchMessageFormatter jsonFormatter, IDispatchMessageFormatter xmlFormatter)
{
this.jsonFormatter = jsonFormatter;
this.xmlFormatter = xmlFormatter;
}
public void DeserializeRequest(Message message, object[] parameters)
{
throw new NotSupportedException("Used for replies only");
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
IDispatchMessageFormatter formatter = this.xmlFormatter;
if (OperationContext.Current.OutgoingMessageProperties.ContainsKey(WebBodyFormatMessageProperty.Name))
{
WebBodyFormatMessageProperty webBody = (WebBodyFormatMessageProperty)OperationContext.Current.OutgoingMessageProperties[WebBodyFormatMessageProperty.Name];
if (webBody != null && webBody.Format == WebContentFormat.Json)
{
formatter = this.jsonFormatter;
}
}
return formatter.SerializeReply(messageVersion, parameters, result);
}
}
Here's my webconfig:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
<services>
<service behaviorConfiguration="CustomBehavior" name="Service.Test">
<endpoint address="" behaviorConfiguration="web" binding="webHttpBinding" contract="Services.ITest" bindingConfiguration="general"/>
</service>
</services>
<bindings>
<webHttpBinding>
<binding name="general" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00"
receiveTimeout="00:10:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="4194304"
maxBufferSize="2147483647" />
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp automaticFormatSelectionEnabled="true" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="CustomBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
So now my problem is, how do i define my custom behavior in code and add it to webconfig? What changes do i need to do? Also if i were to set "BodyStyle = WebMessageBodyStyle.Wrapped" How & Where do i do that?
I see that this question posted very long time ago but may be this will be useful for somebody. I found solution on overcoder.net. All you need is to generate correspondent strings for desired output format and use Stream for result type.
[OperationContract]
[WebGet(UriTemplate = "test?format={format}")]
System.IO.Stream test(string format);
public System.IO.Stream test(string format)
{
ArrayList ar = new ArrayList() { 1, 2, 3 };
if (format == "text")
result = String.Join(",", ar.ToArray());
if (format == "xml")
{
result = #"<soapenv:Envelope>
<soapenv:Header/>
<soapenv:Body>
<result>";
foreach (int i in ar)
result += String.Format("\r\n <item>{0}</item>", i);
result += #"
</result>
</soapenv:Body>
</soapenv:Envelope>";
}
if (format == "json")
result = JsonConvert.SerializeObject(ar, Newtonsoft.Json.Formatting.Indented);
OutgoingWebResponseContext context = WebOperationContext.Current.OutgoingResponse;
context.ContentType = "text/plain";
return new System.IO.MemoryStream(ASCIIEncoding.Default.GetBytes(result));
}

Could not upload Image to WCF Rest service

I am creating a WCF Rest Service to Upload Images from Mobile application. but i am getting
The remote server returned an error: (400) Bad Request. can any one point me what i have done wrong.
Following are my Definitions :
[OperationContract]
[WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, UriTemplate = "/PostImage",Method ="POST")]
PublicMessage PostImage(Upload obj);
[DataContract]
public class Upload
{
[DataMember]
public Stream File { get; set; }
}
Service Definition :
public PublicMessage PostImage(Upload obj)
{
byte[] buffer = StreamToByte(obj.File); //Function to convert the stream to byte array
FileStream fs = new FileStream(#"D:\ShopMonkeyApp\Desert.jpg", FileMode.Create, FileAccess.ReadWrite);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(buffer);
bw.Close();
return new PublicMessage { Message = "Recieved the image on server" };
}
Client Application :
string filePath = #"D:\ShopMonkeyApp\Desert.jpg";
string url = "http://localhost:50268/shopmonkey.svc/PostImage/"; // Service Hosted in IIS
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Accept = "text/xml";
request.Method = "POST";
request.ContentType = "image/jpeg";
using (Stream fileStream = File.OpenRead(filePath))
using (Stream requestStream = request.GetRequestStream())
{
int bufferSize = 1024;
byte[] buffer = new byte[bufferSize];
int byteCount = 0;
while ((byteCount = fileStream.Read(buffer, 0, bufferSize)) > 0)
{
requestStream.Write(buffer, 0, byteCount);
}
}
string result;
using (WebResponse response = request.GetResponse())
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
Console.WriteLine(result);
Web Config :
<system.serviceModel>
<services>
<service name="ShopMonkey.ShopMonkey" behaviorConfiguration="ServiceBehaviour">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address ="" binding="webHttpBinding" contract="ShopMonkey.IShopMonkey" behaviorConfiguration="web">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.behaviorConfiguration="web"
-->
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehaviour">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
<dataContractSerializer maxItemsInObjectGraph="10000000"/>
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
Thanks
Vijay
Increasing the message queue length in web.config solves my issue.
<webHttpBinding>
<binding name="streamWebHttpbinding" transferMode="Streamed" maxReceivedMessageSize="1000000000000" receiveTimeout="01:00:00" sendTimeout="01:00:00" />
</webHttpBinding>
Thanks to all
If you dont have any other properties on the Upload class then change the WCF service method to have a Stream param rather than wrapping it in a class as below:
[OperationContract]
[WebInvoke(UriTemplate = "/PostImage",Method ="POST")]
PublicMessage PostImage(Stream obj);
Then you can use the WebClient class to upload a file directly as shown below:
var c = new System.Net.WebClient();
c.OpenWrite(string.Concat("http://localhost:50268/shopmonkey.svc", "/PostImage"), "POST");
c.Headers[HttpRequestHeader.ContentType] = "image/jpeg";
return c.UploadFile(string.Concat(serviceBaseUrl, resourceUrl), filePath);
Also refer to this link.
UPDATE :
Please find the sample to get your code working below:
[OperationContract]
[WebInvoke(UriTemplate = "/PostImage",Method ="POST")]
PublicMessage PostImage(Upload obj);
[DataContract]
public class Upload
{
[DataMember]
public MemoryStream FileContent { get; set; }
}
Now your method that implements the PostImage looks as follows:
public PublicMessage PostImage(Upload obj)
{
byte[] buffer = new byte[obj.FileContent.Length];
using (FileStream ms = new FileStream(#"D:\ShopMonkeyApp\Temp\Desert.jpg", FileMode.OpenOrCreate))
{
obj.FileContent.Position = 0;
int read = fileInfo.Content.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, read);
}
return new PublicMessage { Message = "Recieved the image on server" };
}
Now since our server side code is complete now moving to the client side part that uploads your file to the server as below:
private string ClientSample()
{
var uploadObject = new Upload();
Image image = Image.FromFile(#"D:\ShopMonkeyApp\Desert.jpg");
MemoryStream ms = new MemoryStream();
uploadObject.FileContent = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
ms.WriteTo(uploadObject.FileContent);
ms.Close();
string responseMessage = null;
var request = WebRequest.Create(http://localhost:50268/shopmonkey.svc/PostImage) as HttpWebRequest;
if (request != null)
{
request.ContentType = "application/xml";
request.Method = method;
}
if(method == "POST" && requestBody != null)
{
byte[] requestBodyBytes;
requestBodyBytes = ToByteArrayUsingDataContractSer<Upload>(requestBody);
request.ContentLength = requestBodyBytes.Length;
using (Stream postStream = request.GetRequestStream())
postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);
}
if (request != null)
{
var response = request.GetResponse() as HttpWebResponse;
if(response.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = response.GetResponseStream();
if (responseStream != null)
{
var reader = new StreamReader(responseStream);
responseMessage = reader.ReadToEnd();
}
}
else
{
responseMessage = response.StatusDescription;
}
}
}
private static byte[] ToByteArrayUsingDataContractSer<T>(T requestBody)
{
byte[] bytes = null;
var serializer1 = new DataContractSerializer(typeof(T));
var ms1 = new MemoryStream();
serializer1.WriteObject(ms1, requestBody);
ms1.Position = 0;
var reader = new StreamReader(ms1);
bytes = ms1.ToArray();
return bytes;
}
NOTE: Make sure that your Upload object both on the client and server have the same namespace and properties defined so that you avoid any deserialization issues.

How do I set the correct content type in a WCF binding without using app.config?

I have created a service reference to the CRM 2011 Organization.svc from a test console application. Everything works perfectly using the binding generated in the app.config. (Example of the service hosted by Microsoft here.)
This now needs to be moved into our "real" application and hosted in a DLL that will be deployed to the GAC. In following the app's conventions, the binding needs to be generated by code.
I've started off trying to use the binding we use for our other WCF services:
BasicHttpBinding binding = new BasicHttpBinding();
binding.SendTimeout = TimeSpan.FromMinutes(1);
binding.OpenTimeout = TimeSpan.FromMinutes(1);
binding.CloseTimeout = TimeSpan.FromMinutes(1);
binding.ReceiveTimeout = TimeSpan.FromMinutes(10);
binding.AllowCookies = true;
binding.BypassProxyOnLocal = false;
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.MessageEncoding = WSMessageEncoding.Text;
binding.TextEncoding = System.Text.Encoding.UTF8;
binding.TransferMode = TransferMode.Buffered;
binding.UseDefaultWebProxy = true;
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
Unfortunately at the point the WCF service is called (using the Execute method with an OrganizationRequest), this error occurs:
System.ServiceModel.ProtocolException: Content Type text/xml; charset=utf-8 was not supported by service http://server:5555/xrmservices/2011/organization.svc. The client and service bindings may be mismatched.
I'm not sure what the specific problem is with the binding, but my attempts at converting it to code have failed with the same error so far. Here's the working binding defined in app.config:
<bindings>
<customBinding>
<binding name="CustomBinding_IOrganizationService">
<security defaultAlgorithmSuite="Default" authenticationMode="SspiNegotiated"
requireDerivedKeys="true" securityHeaderLayout="Strict" includeTimestamp="true"
keyEntropyMode="CombinedEntropy" messageProtectionOrder="SignBeforeEncryptAndEncryptSignature"
messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10"
requireSecurityContextCancellation="true" requireSignatureConfirmation="false">
<localClientSettings cacheCookies="true" detectReplays="true"
replayCacheSize="900000" maxClockSkew="00:05:00" maxCookieCachingTime="Infinite"
replayWindow="00:05:00" sessionKeyRenewalInterval="10:00:00"
sessionKeyRolloverInterval="00:05:00" reconnectTransportOnFailure="true"
timestampValidityDuration="00:05:00" cookieRenewalThresholdPercentage="60" />
<localServiceSettings detectReplays="true" issuedCookieLifetime="10:00:00"
maxStatefulNegotiations="128" replayCacheSize="900000" maxClockSkew="00:05:00"
negotiationTimeout="00:01:00" replayWindow="00:05:00" inactivityTimeout="00:02:00"
sessionKeyRenewalInterval="15:00:00" sessionKeyRolloverInterval="00:05:00"
reconnectTransportOnFailure="true" maxPendingSessions="128"
maxCachedCookies="1000" timestampValidityDuration="00:05:00" />
<secureConversationBootstrap />
</security>
<textMessageEncoding maxReadPoolSize="64" maxWritePoolSize="16"
messageVersion="Default" writeEncoding="utf-8">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</textMessageEncoding>
<httpTransport manualAddressing="false" maxBufferPoolSize="524288"
maxReceivedMessageSize="65536" allowCookies="false" authenticationScheme="Anonymous"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
keepAliveEnabled="true" maxBufferSize="65536" proxyAuthenticationScheme="Anonymous"
realm="" transferMode="Buffered" unsafeConnectionNtlmAuthentication="false"
useDefaultWebProxy="true" />
</binding>
</customBinding>
</bindings>
Does anyone know how to set the correct binding in code and/or read the binding from XML?
I just had the same task to solve. This worked for me (for http).
var security = SecurityBindingElement.CreateSspiNegotiationBindingElement();
security.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Default;
security.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
security.IncludeTimestamp = true;
security.KeyEntropyMode = SecurityKeyEntropyMode.CombinedEntropy;
security.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncryptAndEncryptSignature;
security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
security.LocalClientSettings.CacheCookies = true;
security.LocalClientSettings.DetectReplays = true;
security.LocalClientSettings.ReplayCacheSize = 900000;
security.LocalClientSettings.MaxClockSkew = new TimeSpan(0, 5, 0);
security.LocalClientSettings.MaxCookieCachingTime = new TimeSpan(23, 0, 0, 0);
security.LocalClientSettings.ReplayWindow = new TimeSpan(0, 5, 0);
security.LocalClientSettings.SessionKeyRenewalInterval = new TimeSpan(15, 0, 0);
security.LocalClientSettings.SessionKeyRolloverInterval = new TimeSpan(0, 5, 0);
security.LocalClientSettings.ReconnectTransportOnFailure = true;
security.LocalClientSettings.TimestampValidityDuration = new TimeSpan(0, 5, 0);
security.LocalClientSettings.CookieRenewalThresholdPercentage = 60;
security.LocalServiceSettings.DetectReplays = true;
security.LocalServiceSettings.IssuedCookieLifetime = new TimeSpan(10, 0, 0);
security.LocalServiceSettings.MaxStatefulNegotiations = 128;
security.LocalServiceSettings.ReplayCacheSize = 900000;
security.LocalServiceSettings.MaxClockSkew = new TimeSpan(0, 5, 0);
security.LocalServiceSettings.NegotiationTimeout = new TimeSpan(0, 1, 0);
security.LocalServiceSettings.ReplayWindow = new TimeSpan(0, 5, 0);
security.LocalServiceSettings.InactivityTimeout = new TimeSpan(0, 2, 0);
security.LocalServiceSettings.SessionKeyRenewalInterval = new TimeSpan(15, 0, 0);
security.LocalServiceSettings.SessionKeyRolloverInterval = new TimeSpan(0, 5, 0);
security.LocalServiceSettings.ReconnectTransportOnFailure = true;
security.LocalServiceSettings.MaxPendingSessions = 128;
security.LocalServiceSettings.MaxCachedCookies = 1000;
security.LocalServiceSettings.TimestampValidityDuration = new TimeSpan(0, 5, 0);
var textEncoding = new TextMessageEncodingBindingElement
{
MaxReadPoolSize = 64,
MaxWritePoolSize = 16,
MessageVersion = MessageVersion.Default,
WriteEncoding = System.Text.Encoding.UTF8,
ReaderQuotas = new XmlDictionaryReaderQuotas
{
MaxDepth = 32,
MaxArrayLength = 16384,
MaxBytesPerRead = 4096,
MaxNameTableCharCount = 16384,
MaxStringContentLength = 8192
}
};
var httpTransport = new HttpTransportBindingElement
{
ManualAddressing = false,
MaxBufferSize = 65536,
MaxReceivedMessageSize = 65536,
AllowCookies = false,
AuthenticationScheme = AuthenticationSchemes.Anonymous,
BypassProxyOnLocal = false,
DecompressionEnabled = true,
HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
KeepAliveEnabled = true,
MaxBufferPoolSize = 524288,
ProxyAuthenticationScheme = AuthenticationSchemes.Anonymous,
TransferMode = TransferMode.Buffered,
UnsafeConnectionNtlmAuthentication = false,
UseDefaultWebProxy = true,
};
var binding = new CustomBinding(new List<BindingElement> { security, textEncoding, httpTransport });
var endpoint = new EndpointAddress(_serviceUri);
var service = new OrganizationServiceClient(binding, endpoint);
Creating a custom channel factory is a key part of solving this.
The article Get your WCF client configuration from anywhere is very helpful for reading a .config file from a location of your choice using a custom service client.
The alternative of setting all the values in a very similar way to the app.config format is described in Calling WCF Service using Client Channel Factory which describes how to create a custom binding. I found that not all of the security properties could be set this way (or at least I couldn't find them).

Streamed webHttpBinding is not streamed

I need create WCF REST service for uploading large files. I made endpoint as streamed webHttpBinding, but it have not became streamed.
Service example:
[ServiceContract]
public interface IFiles
{
[OperationContract]
void UploadFile(Stream stream);
}
public class Files : IFiles
{
public void UploadFile(Stream stream)
{
const int BUFFER_SIZE = 64 * 1024;
byte[] buffer = new byte[BUFFER_SIZE];
using (TextWriter logWriter = new StreamWriter("d:\\UploadedFile.log"))
using (Stream fileStream = new FileStream("d:\\UploadedFile", System.IO.FileMode.Create, System.IO.FileAccess.Write))
{
int readBytes = 0;
while (0 < (readBytes = stream.Read(buffer, 0, BUFFER_SIZE)))
{
fileStream.Write(buffer, 0, readBytes);
logWriter.WriteLine("{0}: {1} bytes saved", DateTime.Now, readBytes);
}
}
}
}
Web.config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="WebHttpBinding" maxBufferSize="65536" maxBufferPoolSize="524288"
maxReceivedMessageSize="1073741824" transferMode="Streamed" />
</webHttpBinding>
</bindings>
<services>
<service name="WcfService2.Files">
<endpoint behaviorConfiguration="WebHttpBehavior" binding="webHttpBinding"
bindingConfiguration="WebHttpBinding" name="Files" contract="WcfService2.IFiles" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="WebHttpBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata />
<serviceDebug />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<httpRuntime maxRequestLength="500000" />
</system.web>
</configuration>
Client code:
using (Stream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlString);
request.Method = "POST";
request.ContentType = "application/octet-stream";
//request.ContentLength = fileStream.Length;
//request.AllowWriteStreamBuffering = false;
request.SendChunked = true;
Stream requestStream = request.GetRequestStream();
const int BUFFER_SIZE = 32 * 1024;
byte[] buffer = new byte[BUFFER_SIZE];
int readBytes = 0;
while (0 < (readBytes = fileStream.Read(buffer, 0, BUFFER_SIZE)))
{
requestStream.Write(buffer, 0, readBytes);
Console.WriteLine("{0}: {1} bytes sent", DateTime.Now, readBytes);
System.Threading.Thread.Sleep(200);
}
requestStream.Close();
WebResponse response = request.GetResponse();
}
Code of method UploadFile is invoked only after requestStream.Close() is invoked. Why?
If you want to send it in parts you should add a flush in the while loop after the requestStream.Write()
requestStream.Flush();
This because streams may cache the output till it's nessecary to send it. See http://msdn.microsoft.com/en-us/library/system.io.stream.flush.aspx