Leveraging MSMQ in ASP.NET Applications

[Originally posted by]: http://www.codeguru.com/csharp/.net/net_general/internet/article.php/c19563/Leveraging-MSMQ-in-ASPNET-Applications.htm

Leveraging MSMQ in ASP.NET Applications

By Greg Huber

Have you ever developed a Web application that requires extensive processing? Ever had long running Web pages that often time out in the browser? Most Web developers run into these kinds of issues at some point. As Web application requirements evolve, processing and business logic tend to get more complex. Consequently, it is no surprise that Web applications can lead to frustrating Web experiences.

On the other hand, there may also be processes that simply take time no matter how simple or complex the application. At times, there is processing that typically does not lend itself to occur in a Web application.

The above scenarios require an effective way to initiate long running processes so that inherit problems due to the synchronous nature of the Web and long running processes are minimized or avoided all together.

Requirements

.NET Framework 1.1 (Visual Studio .NET helpful but not required)
Basic familiarity with ASP.NET, .NET Framework
Windows 2000 Professional/Server or Windows XP or 2003 Server

Synchronous vs. Asynchronous Programming Concepts

Before diving into the code, it’s important to understand a few key concepts regarding programming models. Let’s start out with the Synchronous model. In its simplest form, this programming model means that the caller waits until all processing has completed and control is returned.

Alternatively, asynchronous programming means that the caller makes a call and proceeds immediately. A “callback” located in the callers process space may be invoked by the recipient if desired (and available).

The asynchronous concept not only applies to programming models, but also to architectures. Similar to the programming model, a Web application can be architected in such a way that an asynchronous model is achieved. Hence, many of the limitations of the synchronous nature of the Web can be dealt with. In this article, MSMQ will be leveraged to show how to implement such a model.

Overview of MSMQ

MSMQ is the abbreviation for “Microsoft Message Queue”. A queue is simply a message store that is accessible via an API. In .NET, the System.Messaging library is used to interface with an MSMQ.

The primary purpose of MSMQ is to allow for implementing reliable, scalable, high performance distributed applications. Microsoft first released MSMQ with Windows NT 4.0, implemented via COM components. This initial release was fairly complex to deal with in a programmatic fashion. Nevertheless, it introduced many important concepts and benefits, which have been improved upon and carried forward to the current version of MSMQ. Considerable performance gains have also come about since MSMQ 1.0.

For more information, previous version and current features, and support information on MSMQ, etc. please visit the Microsoft MSMQ Center. Also visit the article titled “Accessing Message Queues” for information on reading messages.

Getting Started

The remainder of this article will pose a common scenario, a solution with MSMQ, and walk through the necessary steps to implement the solution.

A Common Scenario

Over time, business requirements evolve, and applications need to be robust enough that they can keep up. Consider the case where a complex calculation evolves to the point where a Web application can no longer process in “Web-time”. In fact, as requirements evolve, data for such a calculation may even come from another system all together, which certainly complicates things.

In other cases, an application you are planning on developing may be a great fit for the Web, with the exception of one or two back-end pieces — for example, generating a report, moving large amounts of data from a data source, etc. These are often activities that Web applications need at some point in time, but due to the lengthy processing time, the Web doesn’t lend itself well.

Unfortunately, there may be little you can do to increase performance / response times in these kinds of scenarios. Often, developers resort to creating a thick-client Windows application that can reside on a desktop-which allows for more control over timeouts. However, many complexities are also introduced, i.e. processing moves from the server to the client and numerous issues may arise including scalability, security, deployment, etc.

One great solution is implementing an asynchronous programming model using MSMQ.

The Proposed Solution: “Disconnected Processing” with MSMQ

At a high level, there are three major logical components. These components may exist on the same machine or could be on completely separate machines.

The ASP.NET client sends a message to the message queue and moves on its merry way. The MSMQ component is a simple message broker; it allows the reading and writing of messages. When a message is read, it is removed from the queue. The .NET service monitors the MSMQ and processes as soon as a message is received. The messages will pile up in the queue until the .NET service is ready to process the next message.

Pre Requisite: Setting up MSMQ

Ensure that you have your Windows 2000/XP CD handy. Simply open the control panel, “add/remove” Windows components, and ensure the Message Queuing Services checkbox is checked. Message queuing must be installed on both the sending (client) and receiving machine (server).

After this step is completed, you will be able to create a private message queue. A private queue is for “workgroup installations”, meaning the computer is not integrated in the Active Directory. There are some limitations that exist in private queues-they are not published whereas public queues are.

Open up the Microsoft Management Console, add/remove the “Computer Management” snap-in, browse to “Services and Applications”, and expand and select the “Message Queuing” node. Right click on “Private Queues” and create a new queue.

Code Walkthrough: Writing a message from the Web

Now that you have set up a private message queue to send and receive messages, you can easily write to it with a Web application. There are a few simple steps to get started. The code for these steps have been included as well-simply unzip to a virtual directory and modify the web.config with your settings.

Important Steps for setting using Messaging in an ASP.NET page

Visual Studio.NET Method Framework Method
Add a reference in your Solution to System.Messaging:
Explicitly add the assembly to your web.config under the :

** Note, you can verify the assembly information by using “gacutil” tool.

Add the line to the top of the class:using System.Messaging; Add the line to the top of the page:<%@ Import Namespace=”System.Messaging” %>

After completing the above steps, your code will be ready to interact with the MSMQ. For demonstration purposes, you can easily create an ASP.NET page with a simple user interface to send a message to a message queue:

This interface shows the two important elements that are necessary for sending messages to an MSMQ-the message queue path and the message itself.

Message Queue Path
A message queue path string must be properly constructed. The syntax of the path can vary widely, depending on the type of queue you are talking to, and where it is located. In the above example, the MSMQ resides on the same machine as the Web server. However, in realistic situations, the MSMQ will reside on another machine. Examples of queue paths:

Queue Type Location message is sent from Example
Public Queue (must belong to ActiveDirectory) Anywhere ServerName\QueueName
Private Queue Same server MSMQ resides on .\private$\QueueName
Private Queue Anyremote location FormatName:DIRECT=OS:machinename\private$\queuename

Message
When using MSMQ with .NET, a message can be any serializable object. When serializing a message to MSMQ, you can use different formatters (including Binary, XML, or even ActiveX which allows for sending COM objects-useful if you want to tap into an existing MSMQ aware application based on COM). You can specify the formatting of your message through the message object that you are sending. For more information on message options, please see the MSDN article on Accessing Message Queues.

In the examples in this article, the default formatter (XML serialization) is used to send a message to the queue, and the message is simply a string object. As mentioned previously, this message could be anything serializable, such as a business object that could then be consumed directly by the listener process.

Code Snippet: Sending a Message

  1. MessageQueue MyMessageQ;
  2. Message MyMessage;
  3. MyMessageQ = new MessageQueue(txtQueuePath.Value);
  4. MyMessage = new Message(txtMessageToSend.Value);
  5. MyMessageQ.Send(MyMessage);
  6. divMessage.InnerHtml= “<b>Message sent
  7. successfully!</b>”;
  8.  

In this scenario, one important reason for using MSMQ is to provide the capability to separate out lengthy processing from the user. Consequently, after sending a message, the Web page has completed processing and control is returned immediately to the user.

Code Walkthrough: Receiving & Processing a Message

To receive a message with MSMQ in the given scenario, a separate process must be running that is watching the queue. A great way to implement this process is to create a simple .NET service that listens to the queue and processes as soon as a message is sent to it.

Code Snippet: Receiving a message in the .NET service:


	MessageQueue MyMessageQ;
		Message MyMessage;

		MyMessageQ = new MessageQueue(_QueuePath);
		MyMessage = MyMessageQ.Receive;	
		WriteStatus("Message Received!");
		DoSomeLongRunningProcess();
		WriteStatus("Processing Finished!");

The “DoSomeLongRunningProcess” method contains code that performs a process that would otherwise cause a timeout if a Web page were running it. Throughout the processing of this method, a database table will be updated (shown later) with status information so at any given point in time, the status of the processing can be determined.

In order to install the service included in the source code, you can simply run the following command after shelling out to the command line:

C:\WINNT\Microsoft.NET\Framework\v1.1.4322\installutil msmqService_listener.exe

Upon successful installation, you will see some informational text scroll by and a confirmation message:

“The Commit phase completed successfully.

The transacted install has completed.”

After installing the listener service, you can open the administrative control panel and browse the current Windows services running on your machine. You should see the service you just installed as pictured below.

After unzipping the service, you will want to ensure that the paths in the MSMQService_Listener.exe.config are correct (instructions are in this file- which is located in the bin directory).

You can now start your service by right clicking “start” and be on your merry way!

Other Considerations

The message queue Receive method waits indefinitely until a message is received on the queue. Depending on the type of processing you are doing, you may want to queue up some worker threads so that multiple messages can be received and processed at once. Consequently, this type of processing can be very robust and scalable.

There are a variety of other methods on the message queue object certainly worth investigating. The following are a few that are noteworthy:

Method Name Description
Peek Performs a non-destructive read a message, meaning the message is not deleted after “peeking”. (Read purges the message)
BeginRead / EndRead, BeginPeak/ End Peak Allows for asynchronous handling of the message. Code will continue running while a message is being received; an event handler will execute when the message has been fully received.
Delete Deletes a message out of the queue.

Code Walkthrough: Checking Status Information

As hinted above, in the scenario where a Web page has triggered a long running process, a user may want status information. One simple technique for providing status information would be to write information (from the .NET service that is doing the processing, as mentioned above) to a database table. The Web application can then check this database table at the request of the user to determine current status.

Database Table

The table above is a simple table that keeps track of a Queue Name and current status. In a real world scenario, you would most likely have more information that you may want to keep track of (such as errors that occurred, information about the message received, etc.). When the listener service receives a message, this status table is updated throughout the processing that occurs.

Code Snippet: Viewing the Table


string dbConnString = 
ConfigurationSettings.AppSettings["AccessDBConnectionString"]; 

//Create connection object 
OleDbConnection oCon = new OleDbConnection(dbConnString); 
string sSQL = "Select * FROM QueueStatus ORDER By ID Desc"; 
OleDbCommand oCmd= new OleDbCommand(sSQL, oCon); 
oCon.Open(); 

dgStatus.DataSource = oCmd.ExecuteReader(); 
dgStatus.DataBind();

In the source code provided, a Web-based interface reads this table and simply displays the current status. To get the latest status, the user must hit the “show status” button.

Here is a sample view of seeing how the status has progressed:

Conclusion

This article demonstrated a simple technique for handling long running Web processes through the Web via Microsoft MSMQ and the System.Messaging framework. MSMQ is a very useful product that developers should consider leveraging in Web applications.

About the Author

Greg Huber is the President and Founder of the Northwest Ohio .NET Users group (http://www.nwnug.com). He is active in the .NET community-speaking at area user groups, serving on the INETA (http://www.ineta.org) user group relations committee, and spearheading community-oriented development initiatives, including Quizzard, a shared-source .NET quiz game. He has been developing and architecting software on the Microsoft platform since 1998, and is currently a lead developer at NFO Worldgroup.

Advertisements

How to Debug Multithreaded Programs in C#

[Originally posted by]: http://www.c-sharpcorner.com/UploadFile/736ca4/how-to-debug-multithread-in-C-Sharp/

Introduction

This article is mainly focused on the process of multithread debugging. We have used thread in C# many times and we ususally ignore the thread debugging process, usually we only check the coding part and trace the error. As we know threading problems are difficult to handle. Like we have an immutable application that handles the many mutable objects (single thread). If we can see the problem of deadlocks, usually a deadlock is the easiest problem to debug. Let’s suppose we get a deadlock error in a stack trace. We can easily fix our code and prevent that error. With deadlocks, the problem is the same locks in different orders. Now let’s see some other aspects of threads.

Race conditions

A race condition is a difficult problem to debug and also a harder task to find from our code. Some other issues make our application cumbersome to handle.

Perhaps this article can help you if you are unfamiliar with the new thread window. In Visual Studio 2012 there is an improvised Thread window. In that Thread window we can debug our multithreaded applications easily. So before we start just try to work through the following topics that we will cover.

  • What threads are.
  • Working with multithreaded console applications.
  • Open the Thread Window
  • Working with the Thread Window

What a thread is

A thread is the smallest sequence of programmed instructions, or we can say that a thread is a small set of executable instructions that can be used to isolate a task from a process. And in some cases we can say that a thread is a component of a process.

We can use threads in C# using the System.Threading namespace.

Working with multiple threads in console applications

In this section we will see a simple console application, were I created 2 threads.

  1. namespace DebugThread
  2. {
  3.     class Program
  4.     {
  5.         static int i = 0;
  6.         static void Main(string[] args)
  7.         {
  8.             Thread T1 = new Thread(MyMethod);
  9.             Thread T2 = new Thread(MyMethod);
  10.             T1.Start();
  11.             T2.Start();
  12.             Console.Read();
  13.         }
  14.         static void MyMethod()
  15.         {
  16.             for (int i = 0; i < 10; i++)
  17.             {
  18.                 i++;
  19.                 Thread.Sleep(5000);
  20.             }
  21.         }
  22.     }
  23. }

Open the Thread Window

Step 1

Insert a Breakpoint in the code.

Thread_Debug

Step 2

Run our application (press F5).

Step 3

Click on the Debug menu and choose the windows option then select Threads as shown in the following image.

ThreadWindow

Working with Thread Window

Now let’s have a look at the Thread window.

As in the preceding image we can see the thread having no name. So, let’s assign the name of the thread.

ThreadName

Now we can see the thread name in Thread Window.

ThreadWindowsHavetHREADnAME

Flagging and Unflagging Thread

  • Go to the Debugging Location toolbar and click the Thread list and see how many threads appear in the list.
  • Go back to the source window and right-click the Thread marker again.
  • On the shortcut menu, point to Flag and then click the thread name and ID number.

FlagThread

To unflag threads

On the Threads window, right-click the line corresponding to the flagged thread. A shortcut menu is displayed. It has options to Unflag and Unflag All.

To unflag the thread, click Unflag. Or click the Red flag icon.

UnFlagThread

To freeze and Thaw threads

Freezing a thread will suspend its execution, in the debugging process. We can say Freeze has suspended the process and Thawing resumes the process. By Freezing and Thawing threads (suspending and resuming), we can have control of the threads running during the debugging process. It helps us when we are solving bugs related to concurrency.

In the Threads window, right-click any thread and then click Freeze.

FreezeThread

Look at the active thread column. The pair of vertical bars now appear there.

Right-click the frozen thread and then click Thaw.

ThawThread

The active thread column and the Suspend column change.

How to customize background color for some web pages opened with eww?

[Originally posted by]: http://emacs.stackexchange.com/questions/2955/how-to-customize-background-color-for-some-web-pages-opened-with-eww

I just installed emacs 24.4 and I’ve started using eww. But one annoying thing is that when I visit google.com I get a grey background which makes text really hard to read for my theme.

This is how it looks: enter image description here

Is there any way I could change the color of the background? I first thought I could customize eww faces but there is no option for this. I’m also curious why is this background color there, in the first place.

shareimprove this question

I’m not sure why the background color is there either, but it seems to be controlled by the function shr-color-check, which is supposed to check that the contrast between the fg and bg is sufficient for the text to be visible. I agree that the readability is not very good in your example. Luckily, there are some variables that can be tweaked: shr-color-visible-luminance-min and shr-color-visible-distance-min. I tried setting

(setq shr-color-visible-luminance-min 70)

and the results are much more readable:

Screenshot of eww window with better contrast

shareimprove this answer
Yep, using shr-color-visible-luminance-min makes the content of the page readable. Thanks. – caisah Nov 14 ’14 at 10:20

How to change the cursor type and color?

[Originally posted by]: http://emacs.stackexchange.com/questions/392/how-to-change-the-cursor-type-and-color

In order to change your cursor or caret, what you want to do is:

Open your .emacs file and this line of code:

(setq-default cursor-type 'bar)

And to change the color:

(set-cursor-color "#ffffff")

Of course, you can change #ffffff to any hexadecimal color.

shareimprove this answer

How to auto copy when a region is selected?

[Originally posted by]: http://emacs.stackexchange.com/questions/17170/how-to-auto-copy-when-a-region-is-selected

The selection can be copied automatically if the OS supports primary selection by setting the below variable.

(setq x-select-enable-primary t)

From C-h v x-select-enable-primary, you get,

Non-nil means cutting and pasting uses the primary selection The existence of a primary selection depends on the underlying GUI you use. E.g. it doesn’t exist under MS-Windows.

To learn even more, visit the relevant info node by doing C-h i g (emacs) Primary Selection.


Another variable setting that goes in tandem with the above is to set the x-select-enable-clipboardto t. Doing that allows you to yank the contents copied from other X11 applications into emacs.

(setq x-select-enable-clipboard t)

When emacs 25.1 is released (supposedly the next stable version after 24.5), the x-select-enable-primary variable name will be deprecated and select-enable-primary must be used instead (removal of that x- prefix). Similarly x-select-enable-clipboard will be deprecated in favor of select-enable-clipboard.

shareimprove this answer

Emacs复制粘贴乱码问题以及修改当前文件编码

【转载】:http://www.cnblogs.com/ilfmonday/p/emacscoding.html

编码修改:

为了和Linux兼容,win环境下将emacs编码修改为utf-8,随意复制了其他关于emacs编码的配置,如下:

(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(setq default-buffer-file-coding-system 'utf-8)

问题与解决:

结果发现emacs和其他win的窗口进行相互的复制粘贴时出现问题,表现为当从其他窗口复制文字,粘贴到emacs中,出现乱码(\xxx这种形式)。细读手册,发现:

selection-coding-system

这个变量用于控制emacs和其他窗口相互发送接收文本的编码,应该就是这个变量的问题,因此在配置文件中将这个变量注释掉,问题解决。

(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
;;(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(setq default-buffer-file-coding-system 'utf-8)

修改当前文件编码:

emacs打开一个文件修改后存储时,会默认使用文件的当前编码存储。如果想更换另外一个编码,可以:

C-x RET c "utf-8" RET C-x C-w RET
;;1 universal-coding-system-argument
;;2 immediately following command 文件另存为

这种交互的方式完成

Attribute Routing in ASP.NET Web API 2

[Originally posted by]: http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2

Attribute Routing in ASP.NET Web API 2
By Mike Wasson|January 20, 2014

1265 of 1397 people found this helpful

Routing is how Web API matches a URI to an action. Web API 2 supports a new type of routing, called attribute routing. As the name implies, attribute routing uses attributes to define routes. Attribute routing gives you more control over the URIs in your web API. For example, you can easily create URIs that describe hierarchies of resources.

The earlier style of routing, called convention-based routing, is still fully supported. In fact, you can combine both techniques in the same project.

This topic shows how to enable attribute routing and describes the various options for attribute routing. For an end-to-end tutorial that uses attribute routing, see Create a REST API with Attribute Routing in Web API 2.

Prerequisites

Visual Studio 2013 or Visual Studio Express 2013

Alternatively, use NuGet Package Manager to install the necessary packages. From the Tools menu in Visual Studio, select Library Package Manager, then select Package Manager Console. Enter the following command in the Package Manager Console window:

Install-Package Microsoft.AspNet.WebApi.WebHost

Why Attribute Routing?

The first release of Web API used convention-based routing. In that type of routing, you define one or more route templates, which are basically parameterized strings. When the framework receives a request, it matches the URI against the route template. (For more information about convention-based routing, see Routing in ASP.NET Web API.

One advantage of convention-based routing is that templates are defined in a single place, and the routing rules are applied consistently across all controllers. Unfortunately, convention-based routing makes it hard to support certain URI patterns that are common in RESTful APIs. For example, resources often contain child resources: Customers have orders, movies have actors, books have authors, and so forth. It’s natural to create URIs that reflect these relations:

/customers/1/orders

This type of URI is difficult to create using convention-based routing. Although it can be done, the results don’t scale well if you have many controllers or resource types.

With attribute routing, it’s trivial to define a route for this URI. You simply add an attribute to the controller action:

[Route("customers/{customerId}/orders")]
public IEnumerable&lt;Order&gt; GetOrdersByCustomer(int customerId) { ... }

Here are some other patterns that attribute routing makes easy.

API versioning

In this example, “/api/v1/products” would be routed to a different controller than “/api/v2/products”.

/api/v1/products
/api/v2/products

Overloaded URI segments

In this example, “1” is an order number, but “pending” maps to a collection.

/orders/1
/orders/pending

Mulitple parameter types

In this example, “1” is an order number, but “2013/06/16” specifies a date.

/orders/1
/orders/2013/06/16

Enabling Attribute Routing

To enable attribute routing, call MapHttpAttributeRoutes during configuration. This extension method is defined in theSystem.Web.Http.HttpConfigurationExtensions class.

using System.Web.Http;

namespace WebApplication
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            // Other Web API configuration not shown.
        }
    }
}

Attribute routing can be combined with convention-based routing. To define convention-based routes, call the MapHttpRoute method.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Attribute routing.
        config.MapHttpAttributeRoutes();

        // Convention-based routing.
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

For more information about configuring Web API, see Configuring ASP.NET Web API 2 .

Note: Migrating From Web API 1

Prior to Web API 2, the Web API project templates generated code like this:

protected void Application_Start()
{
    // WARNING - Not compatible with attribute routing.
    WebApiConfig.Register(GlobalConfiguration.Configuration);
}

If attribute routing is enabled, this code will throw an exception. If you upgrade an existing Web API project to use attribute routing, make sure to update this configuration code to the following:

protected void Application_Start()
{
    // Pass a delegate to the Configure method.
    GlobalConfiguration.Configure(WebApiConfig.Register);
}

For more information, see Configuring Web API with ASP.NET Hosting.

Adding Route Attributes

Here is an example of a route defined using an attribute:

public class OrdersController : ApiController
{
    [Route("customers/{customerId}/orders")]
    [HttpGet]
    public IEnumerable&lt;Order&gt; FindOrdersByCustomer(int customerId) { ... }
}

The string “customers/{customerId}/orders” is the URI template for the route. Web API tries to match the request URI to the template. In this example, “customers” and “orders” are literal segments, and “{customerId}” is a variable parameter. The following URIs would match this template:

You can restrict the matching by using constraints, described later in this topic.

Notice that the “{customerId}” parameter in the route template matches the name of the customerId parameter in the method. When Web API invokes the controller action, it tries to bind the route parameters. For example, if the URI is http://example.com/customers/1/orders, Web API tries to bind the value “1” to the customerId parameter in the action.

A URI template can have several parameters:

[Route("customers/{customerId}/orders/{orderId}")]
public Order GetOrderByCustomer(int customerId, int orderId) { ... }

Any controller methods that do not have a route attribute use convention-based routing. That way, you can combine both types of routing in the same project.

HTTP Methods

Web API also selects actions based on the HTTP method of the request (GET, POST, etc). By default, Web API looks for a case-insensitive match with the start of the controller method name. For example, a controller method named PutCustomers matches an HTTP PUT request.

You can override this convention by decorating the mathod with any the following attributes:

  • [HttpDelete]
  • [HttpGet]
  • [HttpHead]
  • [HttpOptions]
  • [HttpPatch]
  • [HttpPost]
  • [HttpPut]

The following example maps the CreateBook method to HTTP POST requests.

[Route("api/books")]
[HttpPost]
public HttpResponseMessage CreateBook(Book book) { ... }

For all other HTTP methods, including non-standard methods, use the AcceptVerbs attribute, which takes a list of HTTP methods.

// WebDAV method
[Route("api/books")]
[AcceptVerbs("MKCOL")]
public void MakeCollection() { }

Route Prefixes

Often, the routes in a controller all start with the same prefix. For example:

public class BooksController : ApiController
{
    [Route("api/books")]
    public IEnumerable&lt;Book&gt; GetBooks() { ... }

    [Route("api/books/{id:int}")]
    public Book GetBook(int id) { ... }

    [Route("api/books")]
    [HttpPost]
    public HttpResponseMessage CreateBook(Book book) { ... }
}

You can set a common prefix for an entire controller by using the [RoutePrefix] attribute:

[RoutePrefix("api/books")]
public class BooksController : ApiController
{
    // GET api/books
    [Route("")]
    public IEnumerable&lt;Book&gt; Get() { ... }

    // GET api/books/5
    [Route("{id:int}")]
    public Book Get(int id) { ... }

    // POST api/books
    [Route("")]
    public HttpResponseMessage Post(Book book) { ... }
}

Use a tilde (~) on the method attribute to override the route prefix:

[RoutePrefix("api/books")]
public class BooksController : ApiController
{
    // GET /api/authors/1/books
    [Route("~/api/authors/{authorId:int}/books")]
    public IEnumerable&lt;Book&gt; GetByAuthor(int authorId) { ... }

    // ...
}

The route prefix can include parameters:

[RoutePrefix("customers/{customerId}")]
public class OrdersController : ApiController
{
    // GET customers/1/orders
    [Route("orders")]
    public IEnumerable&lt;Order&gt; Get(int customerId) { ... }
}

Route Constraints

Route constraints let you restrict how the parameters in the route template are matched. The general syntax is “{parameter:constraint}”. For example:

[Route("users/{id:int}"]
public User GetUserById(int id) { ... }
[Route("users/{name}"]
public User GetUserByName(string name) { ... }

Here, the first route will only be selected if the “id” segment of the URI is an integer. Otherwise, the second route will be chosen.

The following table lists the constraints that are supported.

Constraint Description Example
alpha Matches uppercase or lowercase Latin alphabet characters (a-z, A-Z) {x:alpha}
bool Matches a Boolean value. {x:bool}
datetime Matches a DateTime value. {x:datetime}
decimal Matches a decimal value. {x:decimal}
double Matches a 64-bit floating-point value. {x:double}
float Matches a 32-bit floating-point value. {x:float}
guid Matches a GUID value. {x:guid}
int Matches a 32-bit integer value. {x:int}
length Matches a string with the specified length or within a specified range of lengths. {x:length(6)}
{x:length(1,20)}
long Matches a 64-bit integer value. {x:long}
max Matches an integer with a maximum value. {x:max(10)}
maxlength Matches a string with a maximum length. {x:maxlength(10)}
min Matches an integer with a minimum value. {x:min(10)}
minlength Matches a string with a minimum length. {x:minlength(10)}
range Matches an integer within a range of values. {x:range(10,50)}
regex Matches a regular expression. {x:regex(^\d{3}-\d{3}-\d{4}$)}

Notice that some of the constraints, such as “min”, take arguments in parentheses. You can apply multiple constraints to a parameter, separated by a colon.

[Route("users/{id:int:min(1)}")]
public User GetUserById(int id) { ... }

Custom Route Constraints

You can create custom route constraints by implementing the IHttpRouteConstraint interface. For example, the following constraint restricts a parameter to a non-zero integer value.

public class NonZeroConstraint : IHttpRouteConstraint
{
    public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, 
        IDictionary&lt;string, object&gt; values, HttpRouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) &amp;&amp; value != null)
        {
            long longValue;
            if (value is long)
            {
                longValue = (long)value;
                return longValue != 0;
            }

            string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
            if (Int64.TryParse(valueString, NumberStyles.Integer, 
                CultureInfo.InvariantCulture, out longValue))
            {
                return longValue != 0;
            }
        }
        return false;
    }
}

The following code shows how to register the constraint:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var constraintResolver = new DefaultInlineConstraintResolver();
        constraintResolver.ConstraintMap.Add("nonzero", typeof(NonZeroConstraint));

        config.MapHttpAttributeRoutes(constraintResolver);
    }
}

Now you can apply the constraint in your routes:

[Route("{id:nonzero}")]
public HttpResponseMessage GetNonZero(int id) { ... }

You can also replace the entire DefaultInlineConstraintResolver class by implementing the IInlineConstraintResolver interface. Doing so will replace all of the built-in constraints, unless your implementation of IInlineConstraintResolver specifically adds them.

Optional URI Parameters and Default Values

You can make a URI parameter optional by adding a question mark to the route parameter. If a route parameter is optional, you must define a default value for the method parameter.

public class BooksController : ApiController
{
    [Route("api/books/locale/{lcid:int?}")]
    public IEnumerable&lt;Book&gt; GetBooksByLocale(int lcid = 1033) { ... }
}

In this example, /api/books/locale/1033 and /api/books/locale return the same resource.

Alternatively, you can specify a default value inside the route template, as follows:

public class BooksController : ApiController
{
    [Route("api/books/locale/{lcid:int=1033}")]
    public IEnumerable&lt;Book&gt; GetBooksByLocale(int lcid) { ... }
}

This is almost the same as the previous example, but there is a slight difference of behavior when the default value is applied.

  • In the first example (“{lcid?}”), the default value of 1033 is assigned directly to the method parameter, so the parameter will have this exact value.
  • In the second example (“{lcid=1033}”), the default value of “1033” goes through the model-binding process. The default model-binder will convert “1033” to the numeric value 1033. However, you could plug in a custom model binder, which might do something different.

(In most cases, unless you have custom model binders in your pipeline, the two forms will be equivalent.)

Route Names

In Web API, every route has a name. Route names are useful for generating links, so that you can include a link in an HTTP response.

To specify the route name, set the Name property on the attribute. The following example shows how to set the route name, and also how to use the route name when generating a link.

public class BooksController : ApiController
{
    [Route("api/books/{id}", Name="GetBookById")]
    public BookDto GetBook(int id) 
    {
        // Implementation not shown...
    }

    [Route("api/books")]
    public HttpResponseMessage Post(Book book)
    {
        // Validate and add book to database (not shown)

        var response = Request.CreateResponse(HttpStatusCode.Created);

        // Generate a link to the new book and set the Location header in the response.
        string uri = Url.Link("GetBookById", new { id = book.BookId });
        response.Headers.Location = new Uri(uri);
        return response;
    }
}

Route Order

When the framework tries to match a URI with a route, it evaluates the routes in a particular order. To specify the order, set the RouteOrderproperty on the route attribute. Lower values are evaluated first. The default order value is zero.

Here is how the total ordering is determined:

  1. Compare the RouteOrder property of the route attribute.
  2. Look at each URI segment in the route template. For each segment, order as follows:
    1. Literal segments.
    2. Route parameters with constraints.
    3. Route parameters without constraints.
    4. Wildcard parameter segments with constraints.
    5. Wildcard parameter segments without constraints.
  3. In the case of a tie, routes are ordered by a case-insensitive ordinal string comparison (OrdinalIgnoreCase) of the route template.

Here is an example. Suppose you define the following controller:

[RoutePrefix("orders")]
public class OrdersController : ApiController
{
    [Route("{id:int}")] // constrained parameter
    public HttpResponseMessage Get(int id) { ... }

    [Route("details")]  // literal
    public HttpResponseMessage GetDetails() { ... }

    [Route("pending", RouteOrder = 1)]
    public HttpResponseMessage GetPending() { ... }

    [Route("{customerName}")]  // unconstrained parameter
    public HttpResponseMessage GetByCustomer(string customerName) { ... }

    [Route("{*date:datetime}")]  // wildcard
    public HttpResponseMessage Get(DateTime date) { ... }
}

These routes are ordered as follows.

  1. orders/details
  2. orders/{id}
  3. orders/{customerName}
  4. orders/{*date}
  5. orders/pending

Notice that “details” is a literal segment and appears before “{id}”, but “pending” appears last because the RouteOrder property is 1. (This example assumes there are no customers named “details” or “pending”. In general, try to avoid ambiguous routes. In this example, a better route template for GetByCustomer is “customers/{customerName}” )

This article was originally created on January 20, 2014