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

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

Related

Set WCF Service endpoints at server side web config for https

I am stuck in very odd situation and do not know how to solve this issue.
I have very simple WCF service working very fine with http BUT now I want to move it to https.
The issue is Server where it needs to be hosted. Server IIS have an alias name "server-test.local" (not "localhost") with http. Its is accessible locally with this alias name. And its mapped to a Domain name with https (example, https://rmt.XXXXXXX.com).
When I deploy my WCF to that server and check WSDL file, it has mapping of the local alias name instead of public domain name.
it is showing http://server-test.local/WCFService/Service.svc (WRONG)
I want mapping like https://rmt.XXXXXXXX.com/WCFService/Service.svc (CORRECT)
Service web.config
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
<pages controlRenderingCompatibilityVersion="4.0"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" messageEncoding="Text">
<readerQuotas maxDepth="2000000" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- 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>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer> <modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
When I add service reference to app. It adds following endpoint which is not conrrect.
Client App.config (endpoint)
<endpoint address="http://server-test.local/WCFService/Service.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IProcessing"
contract="WCFService.IService" name="BasicHttpBinding_IProcessing" />
I am able to access the url and WSDL file through browser but not able to consume any Service methods. I am getting error "There is no endpoint which can accept the message."
I think I am missing something obvious here. Please suggest me changes.
You can try to change some simple steps in the web.config file, you can refer to this post for details.
1.Enable transport level security in the web.config file of the service:
<security mode="Transport">
<transport clientCredentialType="None"/>
</security>
2.Use the bindingConfiguration tag to specify the binding name and the behaviorConfiguration tag to configure the behavior, and then specify the address of the managed service. The code is as follows:
<service name="***" behaviorConfiguration="***">
<endpoint address= https://rmt.XXXXXXXX.com/WCFService/Service.svc
binding="basicHttpBinding"
bindingConfiguration="???"
contract="WCFService.IService"/>
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange"/>
</service>

WCF Service - 404.13 error - though maxAllowedContentLength and maxRequestLength are set

I'm quite new to WCF services, and I just ran into this known issue, when the uploaded file is too big to upload. My situation is strange because I set both maxAllowedContentLength and maxRequestLength to a high number, so it should have no problems with uploading 300 MB files... With small files it works perfectly, so for me it seems like it just forgets about my settings. I tried so many ideas to solve this problem, so maybe I messed up things in my config file, there may be some unnecessary parts, but still I couldn't find the solution.
I'm working with IIS 10 and .Net 4.5.
My WCF Service configuration:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" maxRequestLength="4048576" requestLengthDiskThreshold="4048576" executionTimeout="3600" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="TileServiceBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
<behavior name="FileUploadServiceBehavior">
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ITileService" sendTimeout="01:00:00" maxBufferSize="5000000" />
<binding name="HttpBinding_MTOM"
messageEncoding="Text"
transferMode="Streamed"
maxReceivedMessageSize="4294967294"
maxBufferSize="65536"
maxBufferPoolSize="65536" />
<binding name="BasicHttpBinding_ITileServiceUpload"
closeTimeout="00:01:00"
openTimeout="00:01:00"
receiveTimeout="00:10:00"
sendTimeout="00:10:00"
allowCookies="false"
bypassProxyOnLocal="false"
hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536"
maxBufferPoolSize="524288"
maxReceivedMessageSize="4294967294"
messageEncoding="Text"
textEncoding="utf-8"
transferMode="Streamed"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/AEGIS.TileService/TileService.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITileServiceUpload" contract="AEGIS.TileService.ITileService" name="BasicHttpBinding_ITileServiceUpload" />
</client>
<services>
<service behaviorConfiguration="FileUploadServiceBehavior" name="AEGIS.TileService.TileService">
<endpoint address="winceStream" binding="basicHttpBinding" bindingConfiguration="HttpBinding_MTOM" contract="AEGIS.TileService.ITileService" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<directoryBrowse enabled="true" />
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="4294967295" maxUrl="4294967295" maxQueryString="4294967295" />
</requestFiltering>
</security>
The web.config file from my ASP.NET web app, where the service is referenced.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_ITileService"/>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/AEGIS.TileService/TileService.svc/winceStream" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITileService" contract="TileService.ITileService" name="BasicHttpBinding_ITileService"/>
</client>
My upload method is implemented like this:
public void UploadFile(FileUploadMessage request)
{
string basePath = AppDomain.CurrentDomain.BaseDirectory + #"\Images\";
string serverFileName = Path.Combine(basePath, request.Filename);
using (FileStream outfile = new FileStream(serverFileName, FileMode.Create))
{
const int bufferSize = 65536; // 64K
Byte[] buffer = new Byte[bufferSize];
int bytesRead = request.FileByteStream.Read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
outfile.Write(buffer, 0, bytesRead);
bytesRead = request.FileByteStream.Read(buffer, 0, bufferSize);
}
}
}
Where FileUploadMessage is like this:
[MessageContract]
public class FileUploadMessage
{
[MessageHeader(MustUnderstand = true)]
public string Filename;
[MessageBodyMember(Order = 1)]
public Stream FileByteStream;
}
EDIT 1:
http://ipswitchft.force.com/kb/articles/FAQ/Unable-to-transfer-files-over-30MB-with-the-Web-Transfer-Module-or-Ad-Hoc-Transfer-Module-1307565986108
I found this article about this issue. Maybe my problem is not with the WCF service or config, but with IIS?
I set the requestLimits of the Default App Pool also to 1000000000. The error still appears.
Also in Option 3 the article writes about changing the ApplicationHost.config. The strange thing is that I don't have anything in that file about requestLimits. Maybe that's the main problem?
Your are probably dealing with multiple "issues".
Remember to configure your Server AND Client accordingly!
First, i would configure my .NET runtime (WCF) and IIS behavior
https://stackoverflow.com/a/6472631/1498669
NOTE: maxRequestLength is in KILOBYTES whereas maxAllowedContentLength is in BYTES
I would:
set the default IIS parameter for your specific application (not for the whole machine!) using web.config in your base webfolder to a 'relatively' high value
<system.webServer>
<security>
<requestFiltering>
<!-- maxAllowedContentLength defaults to 30000000 BYTES = 30MB -->
<!-- i use 100MB (100 *1024*1024)-->
<requestLimits maxAllowedContentLength="104857600" />
</requestFiltering>
</security>
</system.webServer>
https://support.microsoft.com/en-us/kb/944981
https://msdn.microsoft.com/en-us/library/ms689462.aspx
set the .NET Framework parameter to my expected 'max' value (at least a bit lower than the iis value) in KB to be able to catch the exception before iis presents me a error website (note: also raise the timeout for big data to transfer).
<system.web>
<!-- maxRequestLength defaults to 4096 KILOBYTES = 4MB -->
<!-- i use 80MB (80 *1024) -->
<!-- please notes that if you use base64 encoded messages -->
<!-- you have to calculate the overhead with CEIL(nBytes/3)*4 -->
<!-- executionTimeout defaults to 110 SECONDS, i use 5 minutes -->
<httpRuntime maxRequestLength="81920" executionTimeout="600" />
</system.web>
https://support.microsoft.com/en-us/kb/295626
https://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntimesection.maxrequestlength.aspx
https://msdn.microsoft.com/en-us/library/e1f13641(v=vs.100).aspx
after that, i configure my endpoints and their bindings
https://msdn.microsoft.com/en-us/library/ms733865.aspx
Also see https://stackoverflow.com/a/36931852/1498669 for the different attributes and their meaning.
As reference, the machine web.configs are located in (depending if you are using 2.0/4.0 and 32/64bits):
32bit / net2.0-3.5
C:\Windows\Microsoft.NET\Framework\v2.0.50727\Config\web.config
32bit / net4.x
C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\web.config
64bit / net2.0-3.5
C:\Windows\Microsoft.NET\Framework64\v2.0.50727\Config\web.config
64bit / net4.x - this mostly gets used in Server2008R2 and higher
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config
in these directories there are also:
web.config.default - you can copy that over web.config to reset your machine config, if you unintentionally altered the machine config!
web.config.comments - for a specific explanation of the attrs/elements
If you want to get in touch to all available elements/attributes - consult your visual studio installation directory, e.g:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\Xml\Schemas\DotNetConfig45.xsd
Offtopic: as additional info to your security settings, see https://msdn.microsoft.com/en-us/library/ff648505.aspx
You need to make similar changes to Web config as well.
You are using "BasicHttpBinding_ITileService" in the web. Therefore in the WCF config and Web config file needs to have similar configuration.
<binding name="BasicHttpBinding_ITileService"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
</binding>

Error while consuming WCF service in Windows Service

I have added wcf service in "Windows Service" as service reference. but when i try to create instance it simply gives me following error
"Could not find default endpoint element that references contract
'ServiceReference1.IClientService' in the ServiceModel client
configuration section. This might be because no configuration file was
found for your application, or because no endpoint element matching
this contract could be found in the client element."
Code
pushNotification push_notification = new pushNotification();
var proxy = new ServiceReference1.ClientServiceClient();
using (var scope = new OperationContextScope(proxy.InnerChannel))
{
// Add a HTTP Header to an outgoing request
HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
requestMessage.Headers["Authorization"] = "Push Notification";
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
push_notification = proxy.GetPendingNotification();
}
app.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:4567/ClientService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IClientService"
name="BasicHttpBinding_IService1" behaviorConfiguration="webHttpBehavior" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="webHttpBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
Be sure you put the endpoint information in your main App.config or Web.config.
If you've added the service reference in a separate project you need to copy the config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IService1" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:4567/ClientService.svc" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding_IService1" contract="ServiceReference1.IClientService"
name="BasicHttpBinding_IService1" />
</client>
</system.serviceModel>
In your startup project App.config/Web.config!

WCF Concurrency?

I have a WCF service deployed to IIS 7 and the client. I thought the service is configured to handle concurrency. When I tested with two client, it took double the amount of time. I have spent hours and not yet able to figure out where I missed it. Any help/suggestions would be appreciated. Service1.svc.cs looks like this:
[ServiceBehavior( ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
[CallbackBehavior(UseSynchronizationContext=false)]
public class Service1 : IService1
{
public byte[] DownloadFile()
{
byte[] byt = File.ReadAllBytes(#"C:\Temp\TestFile.pdf");
System.Threading.Thread.Sleep(1000);
return byt;
}
}
Configuration:
<system.net>
<connectionManagement>
<add address="*" maxconnection="100"/>
</connectionManagement>
</system.net>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<processModel autoConfig="false" maxWorkerThreads="1400" maxIoThreads="1400" minWorkerThreads="2"/>
<httpRuntime minFreeThreads="1000" minLocalRequestFreeThreads="1000"/>
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Service1Binding" maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647" transferMode="Streamed">
<readerQuotas maxDepth="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="DocService.Service1">
<endpoint address="http://localhost/DocService/Service1.svc" binding="basicHttpBinding"
bindingConfiguration="" name="Service1Binding" bindingName="Service1Binding"
contract="DocService.IService1" />
<endpoint address="http://localhost/DocService/mex" binding="mexHttpBinding"
name="mexpoint" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceThrottling maxConcurrentCalls="100" maxConcurrentInstances="100" maxConcurrentSessions="100"/>
</behavior>
</serviceBehaviors>
</behaviors>
The requests are taking much longer than 1s sleep time and the read time of, say, 10mb file. They should complete in maybe 1.1-2s There is something fishy here.
Comment out the read and return a new byte[0]. Does it take 1.0s now? Do you have concurrency now?
Edit: What client are you using?
Edit 2: Responding to your comment, the file transfer is not limiting concurrency in some way. WCF does not care what you do inside your service method. It knows nothing about files. The problem is that your disk is too slow and that serializing 36mb is probably slow too! You server is just too slow! You can find out, if the disk or the serializing is the problem by replacing the IO with new byte[1024*1024*36].

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

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>

Categories