Solving development problems  |  About this blog

Archive for the ‘wcf’ tag

Increasing maximum request length for WCF REST Web Service with ASP .NET 4.0

Recently we have extended a web service with method for uploading user’s profile image. So far the service was working fine with less amount of data, i.e. name, address and description. First image upload test with the new method resulted with 400 Bad Request. Breakpoints were set in WCF method but debugger did not stop there, not even entered the method.

Default configuration

WCF service had been configured for REST using default webHttpBinding configuration in web.config

<configuration>
  ...
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="ApiBehavior" />
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="Avivo.Web.Services.ApiServiceBehavior">
         <serviceMetadata httpGetEnabled="true" />
         <serviceDebug includeExceptionDetailInFaults="false" />
         <serviceTimeouts transactionTimeout="00:05:00" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <services>
      <!-- API v1.0 -->
      <service behaviorConfiguration="Avivo.Web.Services.ApiServiceBehavior"
name="Avivo.Web.Services.ApiService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:1234/api/v1" />
          </baseAddresses>
        </host>
        <endpoint address="" binding="webHttpBinding"
contract="Avivo.Web.Services.IApiService" behaviorConfiguration="ApiBehavior" />
      </service>
    </services>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true">
      <baseAddressPrefixFilters>
        <add prefix="http://localhost:1234/api/v1"/>
      </baseAddressPrefixFilters>
    </serviceHostingEnvironment>

  </system.serviceModel>
  ...
</configuration>

Identifying the problem

Images can be quite large (few MB), especially when comparing with text size (few KB). At first it was assumed the web service call has exceeded maximum request length limit. To confirm the assumption we analyzed WCF traffic using SvcTraceViewer.

Enabling WCF tracing in web.config

<configuration>
  ...
  <!-- Use SvcTraceViewer for debugging WCF services -->
  <system.diagnostics>
    <trace autoflush="true" />
    <sources>
      <source name="System.ServiceModel" switchValue="Information,
ActivityTracing" propagateActivity="true">
        <listeners>
          <add name="sdt" type="System.Diagnostics.XmlWriterTraceListener"
initializeData="d:\temp\wcf-trace.svclog" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
  ...
</configuration>

When the tracing is set each request to web service will write entry to d:\temp\wcf-trace.svclog in this case. The report file can be opened with SvcTraceViewer found in %ProgramFiles%\Microsoft SDKs\Windows, e.g. “c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\SvcTraceViewer.exe”

Entries in SvcTraceViewer marked with red represents errors. The problematic request was logged with error message:

The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element.

Identifying that assumption was right and the upload request exceeded default 65 KB limit.

Increasing request limit quota

Customizing webHttpBinding in web.config and referencing with bindingConfiguration in endpoint element

<configuration>
        ...
  <system.serviceModel>
        ...
    <bindings>
      <!-- Customizations for REST service -->
      <webHttpBinding>
        <!-- Limits set to 10 MB (specified value in bytes) -->
        <binding name="ApiQuotaBinding" maxReceivedMessageSize="10485760"
maxBufferPoolSize="10485760" maxBufferSize="10485760" closeTimeout="00:03:00"
openTimeout="00:03:00" receiveTimeout="00:10:00" sendTimeout="00:03:00">
          <readerQuotas maxDepth="32" maxStringContentLength="10485760"
maxArrayLength="10485760" maxBytesPerRead="10485760" />
          <security mode="None" />
        </binding>
      </webHttpBinding>
    </bindings>

    <services>
      <!-- API v1.0 -->
      <service behaviorConfiguration="Avivo.Web.Services.ApiServiceBehavior"
name="Avivo.Web.Services.ApiService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:1234/api/v1" />
          </baseAddresses>
        </host>
        <!-- Added attribute 'bindingConfiguration' -->
        <endpoint address="" bindingConfiguration="ApiQuotaBinding" binding="webHttpBinding"
contract="Avivo.Web.Services.IApiService" behaviorConfiguration="ApiBehavior" />
      </service>
    </services>

  </system.serviceModel>
  ...
</configuration>

Additionally httpRuntime limits must also be set because web service is running in ASP .NET compatibilty mode. Note that maxRequestLength has value in kilobytes.

<configuration>
  ...
  <system.web>
    <httpRuntime maxRequestLength="10240" />
  </system.web>
  ...
</configuration>

Testing

Finding the solution was not straightforward, it took some time searching the web and reading documentation. Finally after figuring out the described config in this post we solved the problem with success.

Written by developer

October 26th, 2011 at 7:50 pm

The service cannot be activated due to an exception during compilation. The exception message is: This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.

You can solve this issue by adding the following code to your web.config:

<system.serviceModel>
	...
	<serviceHostingEnvironment>
	  <baseAddressPrefixFilters>
	  	<add prefix="http://sample.domain.tld/Sample/"/>
	  </baseAddressPrefixFilters>
	</serviceHostingEnvironment>
	...
</system.serviceModel>

Allowing WCF services (svc extension) in IIS7

  1. First, click on your website (or IIS7 website root)
  2. Click on MimeTypes and enter “.svc” and “application/octet-stream” and save
  3. In your project add this to your web.config in <httpHandlers> section:
    <add name=”svc-Integrated” path=”*.svc” verb=”*” type=”System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″ preCondition=”integratedMode” />
    <add name=”svc-ISAPI-2.0″ path=”*.svc” verb=”*” modules=”IsapiModule” scriptProcessor=”%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll” preCondition=”classicMode,runtimeVersionv2.0,bitness32″ />

Written by Avivo

July 12th, 2010 at 9:17 pm

Silverlight 2.0 – Invoke method with Reflection

When deciding whether to create a rich graphical web application with lots of animations either with Silverlight or ASP .NET, Silverlight definitely wins. But when deciding whether put a database in first place then server side scripts (i.e. ASP .NET) have the advantage.

Anyway, if you are accessing database from Silverlight you’ve probably came across WCF or other  web services. Let’s say you have 100 tables and want to use WCF. Each table has Select, Insert, Update and Delete methods generated like InsertUser(User item). Visual Studio 2008 can automatically generated WCF proxy classes in Silverlight which are asynchronous. Suddenly, handling application logic and database becomes complex for development.

Those methods have similarities - Select, Insert, Update and Delete are repeated but for different table names. Idea is to use System.Reflection to simply and minimize development time. What the Reflection classes do is they use run time variables (i.e. string, int, etc.) to dynamically invoke methods according to situation in run time (cannot be determined in design time while developing).

Let’s say you have a method InsertCustomer(Customer item) in WCF and Visual Studio generates InsertCustomerAsync(Customer item) for Silverlight. Application can generate “InsertCustomerAsync” as string on demand. Then a method invoke by string is needed:

using System.Reflection;

//MyWebService is WCF proxy class and Customer is data entity

MethodInfo methodInfo = typeof(MyWebService).GetMethod(“InsertCustomerAsync”, new Type[] { typeof(Customer) });

methodInfo.Invoke(con, BindingFlags.Public | BindingFlags.Instance, null, new object[] { this.item, }, null);

Then a “completed” event needs to be caught:

MethodInfo handlerInfo = typeof(ReflectionDemo<T>).GetMethod(“SaveHandler”, BindingFlags.NonPublic | BindingFlags.Instance);
EventInfo eventInfo = typeof(MyWebService).GetEvent(eventName);
eventInfo.AddEventHandler(con, Delegate.CreateDelegate(eventInfo.EventHandlerType, this, handlerInfo));

Putting all code together:

public class ReflectionDemo<T> where T : new()
{
private T item;

public bool IsUpdate
{
get;
set;
}

public void Save()
{
try
{
if (this.item != null)
{
//Get names
string methodName = (this.IsUpdate ? “Update” : “Insert”) + typeof(T).Name + “Async”; //e.g. UpdateCustomerAsync
string eventName = (this.IsUpdate ? “Update” : “Insert”) + typeof(T).Name + “Completed”; //e.g. UpdateCustomerCompleted
string eventArgsName = (this.IsUpdate ? “Update” : “Insert”) + typeof(T).Name + “CompletedEventArgs”; //e.g. UpdateCustomerCompletedEventArgs

//Create a connection
MyWebService con = new MyWebService();

//Attach an event handler in run time retrieved event (e.g. something like “con.UpdateCustomerCompleted += …” at design time)
MethodInfo handlerInfo = typeof(ReflectionDemo<T>).GetMethod(“SaveHandler”, BindingFlags.NonPublic | BindingFlags.Instance);
EventInfo eventInfo = typeof(MyWebService).GetEvent(eventName);
eventInfo.AddEventHandler(con, Delegate.CreateDelegate(eventInfo.EventHandlerType, this, handlerInfo));

//Invoke method in run time (e.g. something like “con.UpdateCustomerAsync(this.item);” at design time)
MethodInfo methodInfo = typeof(MyWebService).GetMethod(methodName, new Type[] { typeof(T) }); //From overloaded methods get the one with single parameter
methodInfo.Invoke(con, BindingFlags.Public | BindingFlags.Instance, null, new object[] { this.item, }, null); //Invoke the method immediately
}
}
catch (Exception ex)
{
//Exception may be thrown in various situations (e.g. method cannot be found)
//Insert breakpoint here while debugging
}
}

protected void SaveHandler(object sender, EventArgs args)
{

//Handle event logic here
//Sample how to cast to a derived EventArgs with known properties:

Type type = args.GetType();
Exception ex = type.GetProperty(“Error”).GetValue(args, null) as Exception ?? null;
Customer item = (Customer)type.GetProperty(“Customer”).GetValue(args, null);
}

Written by Avivo

July 3rd, 2009 at 2:45 pm