How to Send Large File From Client To Server Using WCF? - c#

How to Send Large File From Client To Server Using WCF in C#? Below the configuration code.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="HttpStreaming_IStreamingSample"
maxReceivedMessageSize="67108864"
transferMode="Streamed">
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint
address="http://localhost:4127/StreamingSample.svc"
binding="basicHttpBinding"
bindingConfiguration="HttpStreaming_IStreamingSample"
contract="StreamingSample.IStreamingSample"
name="HttpStreaming_IStreamingSample" />
</client>
</system.serviceModel>

You need to check out streaming, as Dzmitry already pointed out.
In order to be able to send large files as a stream to your service, you'll need to:
create a service method that accepts a Stream as its input parameter
create a binding configuration (on both the server and the client) which uses transferMode=StreamedRequest
create a stream in your client and send it to the service method
So first off, you need a method in your service contract:
[ServiceContract]
interface IYourFileService
{
[OperationContract]
void UploadFile(Stream file)
}
Then you need a binding configuration:
<bindings>
<basicHttpBinding>
<binding name="FileUploadConfig"
transferMode="StreamedRequest" />
</basicHttpBinding>
</bindings>
and a service endpoint on your service using that binding configuration:
<services>
<service name="FileUploadService">
<endpoint name="UploadEndpoint"
address="......."
binding="basicHttpBinding"
bindingConfiguration="FileUploadConfig"
contract="IYourFileService" />
</service>
</services>
and then, in your client, you need to open e.g. a filestream and send that to the service method without closing it.
Hope that helps!
Marc

You can take a look at WCF Streaming feature.

In addition to increasing readerQuota settings (mentioned above) I had to also up the maxRequestLength inside the httpRuntime attribute.
<system.web>
<httpRuntime maxRequestLength="2097151" />
</system.web>

Related

C# using different endpoints to the same WebService

We have a setup, with a dev- test- and production environment. So when development and testing is done, each server has the same WebServices.
This is my first time doing so, but on the dev. environment I’ve written a WebService, and a C# client, using the Visual Studio (2017) ‘Add Service Reference’ feature. So I have an app.config file like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BizTalkInterfaceServiceSoapBinding">
<security mode="Transport">
<transport clientCredentialType="Basic" proxyCredentialType="Basic" realm="" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://xxx.xxx.xxx.xxx:xxxxx/and/so/on"
binding="basicHttpBinding" bindingConfiguration="BizTalkInterfaceServiceSoapBinding"
contract="ServiceReference.BizTalkInterface" name="BizTalkInterfacePort" />
</client>
</system.serviceModel>
</configuration>
And a Connected Services->ServiceReference structure, with a .wsdl, configuration.svcinfo, configuration91.svcinfo and Reference.svcmap files. I don’t know if there is any point in showing the contents of these files?
I initialize the client like this:
protected BizTalkInterfaceClient client;
protected ServiceBase()
{
client = new BizTalkInterfaceClient("BizTalkInterfacePort");
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
client.ClientCredentials.UserName.UserName = "xxx#xxxdomain";
client.ClientCredentials.UserName.Password = "xxxxxx";
}
Anyhow - This is all well and good, and works fine.
If you haven’t figured it out yet :-), I would like to define two other named endpoints, but I’m unsure on how to do it. Is there a wizard like way to do it, or do I have to copy/past the endpoint in the app.config and configuration files?
Any help would be greatly appreciated. Thanks a lot in advance.
You should be able to copy and paste this endpoint in your <client> node:
<endpoint address="https://xxx.xxx.xxx.xxx:xxxxx/and/so/on"
binding="basicHttpBinding" bindingConfiguration="BizTalkInterfaceServiceSoapBinding"
contract="ServiceReference.BizTalkInterface" name="BizTalkInterfacePort" />
and just give it a different name.
Also, when you initialize you client you would use the corresponding name here:
client = new BizTalkInterfaceClient("BizTalkInterfacePort");
example:
<endpoint address="https://xxx.xxx.xxx.xxx:xxxxx/and/so/on"
binding="basicHttpBinding" bindingConfiguration="BizTalkInterfaceServiceSoapBinding"
contract="ServiceReference.BizTalkInterface" name="BizTalkInterfacePortProd" />
client = new BizTalkInterfaceClient("BizTalkInterfacePortProd");
If your service has multiple service endpoint, it should be like
<service name="Service.CalculatorService" >
<endpoint address="http://localhost:3721/calculator" binding="basicHttpBinding" bindingConfiguration="ECMSBindingConfig" contract="ServiceInterface.ICalculatorService"></endpoint>
<endpoint address="http://localhost:4000/calculator" binding="wsHttpBinding" contract="ServiceInterface.ICalculatorService"></endpoint>
</service>
And then you could add reference to the service using wsdl address.
After adding reference, there should be two endpoint in your client with endpoint name, like
<endpoint address="http://localhost:3721/calculator" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ICalculatorService" contract="Calculator.ICalculatorService"
name="BasicHttpBinding_ICalculatorService" />
<endpoint address="http://localhost:4000/calculator" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_ICalculatorService" contract="Calculator.ICalculatorService"
name="WSHttpBinding_ICalculatorService">
Then in your client , you could initialize your client using the name of your configuration just as Popo has written.

Service should only be accesible between certain times

I need to create a WCF service that gets some data out of a database. This service should only be accessible at night, for some reason. I have been told this should be possible by some code in web.config, but I have no idea how.
Not sure if there's a way to define in web.config, but it seems like you can use PowerShell to schedule and terminate the service.
MSDN blog post on scheduling background jobs
It's not possible in web.config. This is a highly unusual requirement. Certainly not built in.
Just go like this:
if (DateTime.Now.Hour >= 22)
throw new FaultException("ServiceUnavailable");
For a client, you would want to adjust the sendTimeout attribute of a binding element. For a service, you would want to adjust the receiveTimeout attribute of a binding elemnent.
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="longTimeoutBinding"
receiveTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="longTimeoutService"
behaviorConfiguration="longTimeoutBehavior">
<endpoint address="net.tcp://localhost/longtimeout/"
binding="netTcpBinding" bindingConfiguration="longTimeoutBinding" />
</service>
Let me know if this answers your question.

WCF service errors out on other machines in the same network

I developed a C# console application that consumes a WCF service. All works fine on the local machine. When I created the set up files and distributed the exe and exe.config files, the application errors out on other machines on the same network with the below error:
The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state..
The WCF service endpoint URL - http://inblrlwssc251.wdf.corp:7980/AfariaService/Server is accessible form other machines as well. Unsure what can be going wrong.
The configuration for the service looks as below, I use the WSHTTP binding:
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="true"
logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
</diagnostics>
<bindings>
<netNamedPipeBinding>
<binding name="NetNamedPipeBinding_IServerService" />
</netNamedPipeBinding>
<netTcpBinding>
<binding name="NetTcpBinding_IServerService">
<security mode="Message" />
</binding>
</netTcpBinding>
<wsHttpBinding>
<binding name="WSHttpBinding_IServerService" />
</wsHttpBinding>
</bindings>
<!--
Modify the "adress" in each of the endpoint tags based on where the Afaria API service is hosted
-->
<client>
<endpoint address="http://inblrlwssc251:7980/AfariaService/Server"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServerService"
contract="AfariaServerService.IServerService" name="WSHttpBinding_IServerService">
</endpoint>
<endpoint address="net.tcp://inblrlwssc251:7982/AfariaService/Server"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IServerService"
contract="AfariaServerService.IServerService" name="NetTcpBinding_IServerService">
</endpoint>
<endpoint address="net.pipe://localhost/AfariaService/Server"
binding="netNamedPipeBinding" bindingConfiguration="NetNamedPipeBinding_IServerService"
contract="AfariaServerService.IServerService" name="NetNamedPipeBinding_IServerService">
</endpoint>
</client>
</system.serviceModel>
Any help or a pointer in the right direction will be very much appreciated.
I know that this is old and you said it is resolved, but for posterity's sake this is not typically the result of passing incorrect credentials. Normally this is a result of the response from the server responding with more data that you've configured to accept in your buffers, exceeding the maxitemsinobject graph, or the response from the server taking too long, which causes an exception, which is handled... and this exception is the result of the next call (as fejesjoco and Tim pointed out).
When this occurs, it is best to reinitialize the client/serviceclient object (for this api, also call initContext) and then try the call again.

Reading byte array from a SQL database through WCF - maxArrayLength issue

I have a WCF service which is supposed to return a List to my client application. One of the columns in the database are byte[]. When I try to return this list of Object, I only get a NetDispatcherFaultException with this inner-exception:
"The maximum array length quota (16384) has been exceeded while
reading XML data. This quota may be increased by changing the
MaxArrayLength property on the XmlDictionaryReaderQuotas object used
when creating the XML reader. Line 1, position 38697."
I have googled after this and found a that I should increase the maxArrayLength in the web.config, so I did:
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
<add binding="basicHttpBinding" scheme="http"
bindingConfiguration="CrudserviceBinding" />
</protocolMapping>
<bindings>
<basicHttpBinding>
<binding name="CrudserviceBinding" maxReceivedMessageSize="52428800" >
<readerQuotas maxStringContentLength="10242880"
maxArrayLength="10242880" />
</binding>
</basicHttpBinding>
</bindings>
This is my app.config on the client side:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ICrudService">
<readerQuotas maxStringContentLength="5242880"
maxArrayLength="52428800" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/My.Project/CrudService.svc"
binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_ICrudService"
contract="MobileCrudService.ICrudService"
name="BasicHttpBinding_ICrudService" />
</client>
</system.serviceModel>
</configuration>
When I try this once more, the WCF service returns the same exception. Can anybody explain how I should deal with this?
If you are calling the service in a class Library on the Client, make sure you are changing the actual Application .config file. Do not use
Products/ProductName/Main/Source/Project_Name/bin/Debug/ProjectName.dll.config
instead use
Products/ProductName/Main/Source/Project_EXE_Name/bin/Debug/YourExe.config

Configure WCF Client to consume a WCF Service using HTTP GET

I have a WCF Service which allows only HTTP GET requests:
[WebInvoke(Method="GET", ResponseFormat=WebMessageFormat.Json)]
public string GetAppData()
The service is exposed using webHttpBinding
<system.serviceModel>
<bindings>
<webHttpBinding>
<binding name="AppSvcBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
I have my client whose config looks like
<system.serviceModel>
<client>
<endpoint address="http://localhost/AppService/Service.svc"
binding="webHttpBinding"
bindingConfiguration="webHttpBindingConfig"
contract="AppSvc.IService"
behaviorConfiguration="AppSvcBehavior"
name="AppSvcClient">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
</client>
<bindings>
<webHttpBinding>
<binding name="webHttpBindingConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="AppSvcBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
My client code is a simple
ServiceClient client = new ServiceClient("AppSvcClient");
String result = client.GetAppData();
On executing this code I get the error:
The remote server returned an unexpected response: (405) Method Not Allowed.
I checked with fiddler and found that my client is sending a POST message whereas the service expects a GET hence the error.
I wish to know how to configure the client so that is sends GET request to the service.
Use WebGet instead of WebInvoke
Edit
Start by changing your method to this:
[WebInvoke(Method="GET", ResponseFormat=WebMessageFormat.Json,UriTemplate = "/")]
public string GetAppData()
Make sure that webhttpbinding is specified on the server side.
This fixes it on the server side.
Take a backup of your client code.
On the client side delete the service reference. Make sure that all config is removed.
Then add the service reference again. Now it shoud be OK.
I had a similar problem where the generated proxy service interface on the client was missing the WebGet attribute on my methods.
I added the attribute manually and it resolved the problem.
So it seems like the best current solution is to extract the service interfaces into a separate assembly and then share this assembly between the server and its clients.
The automatic proxy generator seems to be buggy.

Categories