Solving development problems  |  About this blog

Archive for the ‘ASP.NET’ Category

Set IIS binding manually (add and remove IIS binding)

We had an issue that we need to add or remove IIS 7 or IIS 7.5 additional bindings on one web application and we wanted to do this from one of our ASP.NET MVC applications.

It is possible so you need to use IIS system program appcmd.exe (you can find it in C:\Windows\System32\inetsrv\ (we suggest you to put this into your PATH variable)

Adding additional bindings

You want to add your-subdomain.your-domain.com binding to your IIS 7 app named your-domain.com

C:\Windows\System32\inetsrv\appcmd set site /site.name: your-domain.com /+bindings.[protocol='http',bindingInformation='*:80:your-subdomain.your-domain.com']

Removing existing bindings

You want to remove your-subdomain.your-domain.com binding from your IIS 7 app named your-domain.com (please notice - sign in front of bindings word)

C:\Windows\System32\inetsrv\appcmd set site /site.name: your-domain.com /-bindings.[protocol='http',bindingInformation='*:80:your-subdomain.your-domain.com']

And that’s it but if you want to run it from ASP.NET you could try to use Process and ProcessInfo classes to run DOS command but there are some permissions problems (we didn’t investigated much).

Other (alternative way that we tried is directly from the code)
You will need to reference this DLL: c:\Windows\System32\inetsrv\Microsoft.Web.Administration.dll

using (ServerManager serverManager = new ServerManager())
{
  if (serverManager.Sites == null)
    throw new SimpleException("There are no IIS applications!");

  var esponceApp = serverManager.Sites.FirstOrDefault(
x => x.Name == Settings.IISAppName);
  if (esponceApp != null)
  {
    BindingCollection bindingCollection = esponceApp.Bindings;
    Binding binding = bindingCollection.CreateElement("binding");
    binding["protocol"] = "http";
    binding["bindingInformation"] =
string.Format(@"{0}:{1}:{2}", "*", "80", this.DomainName);

    //Remove this binding if already exists.
    int oldBindingIndex = -1;
    int bindingIndex = -1;
    foreach (Binding currentBinding in esponceApp.Bindings)
    {
      if (currentBinding.BindingInformation ==
binding["bindingInformation"].ToString())
      {
        bindingIndex = esponceApp.Bindings.IndexOf(currentBinding);
      }
      if (!string.IsNullOrEmpty(oldDomainName) &&
      currentBinding.BindingInformation ==
string.Format(@"{0}:{1}:{2}", "*", "80", oldDomainName))
      {
        oldBindingIndex = esponceApp.Bindings.IndexOf(currentBinding);
      }
    }
    if (bindingIndex != -1)
    {
      esponceApp.Bindings.RemoveAt(bindingIndex);
    }
    if (oldBindingIndex != bindingIndex && oldBindingIndex != -1)
    {
      esponceApp.Bindings.RemoveAt(oldBindingIndex);
    }

    //Add this bindings
    bindingCollection.Add(binding);
    serverManager.CommitChanges();
  }
}
}
catch
{
throw new SimpleException("Could not add binding into IIS application!");
}

Important!
Set identity of your app’s Application Domain from Advanced Settings > Process Model > Identity > Change “ApplicationPoolIdentity” to “Local System”

Investigate also security implications if you are not running this in Intranet….

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

Create random web hex color in C# / ASP.NET MVC

Random random = new Random();
int red = random.Next(0, 255);
int green = random.Next(0, 255);
int blue = random.Next(0, 255);
string hexColour = String.Format("#{0:X2}{1:X2}{2:X2}", red, green, blue);

Written by Avivo

April 22nd, 2011 at 11:46 pm

How to trim leading and trailing HTML spaces in C#

Some HTML WYSIWYG editors create ‘br’ tags or leave ‘&nbsp;’ garbage spaces when no content is entered. Described TrimWhiteSpaces method is useful when you need to determine if user left blank content in WYSIWYG editor or if you just want to clean HTML code.

TrimWhiteSpaces accepts raw HTML content and removes white spaces, tabs, new line characters, ‘br’ tags and ‘&nbsp;’ chunks from before and after the actual content.

public static string TrimWhiteSpaces(string html)
{
  string result = html;

  //Remove leading spaces
  result = Regex.Replace(result, @"^(?<leading>(\s|\r|\n|\<br\s*/?\>|&nbsp;)*)", "",
RegexOptions.IgnoreCase);

  //Remove trailing spaces
  result = Regex.Replace(result, @"(?<trailing>(\s|\r|\n|\<br\s*/?\>|&nbsp;)*)$", "",
RegexOptions.IgnoreCase);

  return result;
}
Example:
Input:

&nbsp;<br /><BR   ><BR> &nbsp;
&nbsp;&nbsp;<br />
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
&nbsp;&nbsp;<br />
<p>Pellentesque lorem neque, accumsan eget euismod ut, tristique et odio.</p>
&nbsp;<br /> <br>
&nbsp;
Output:


<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
&nbsp;&nbsp;<br />
<p>Pellentesque lorem neque, accumsan eget euismod ut, tristique et odio.</p>

Written by developer

December 13th, 2010 at 1:27 pm

Parsing URL query string into key-value pairs in C#

Imagine you have URL something like this:

http://www.yourdomain.com?param1=value1&param2=value2&param3=value3&param4=value4

and you want to get key-value pairs such as

  • {“param1″, “param2″, “param3″, “param4″}
  • {“value1″, “value2″, “value3″, “value4″}

It is easy to do using system function:

using System.Collections.Specialized;
NameValueCollection query = HttpUtility.ParseQueryString(queryString);
Response.Write(query["param1"]);

Written by Avivo

December 3rd, 2010 at 1:08 pm