Wednesday, May 30, 2012

Implementing message handlers to track your ASP.NET Web API usage

Implementing message handlers to track your ASP.NET Web API usage

Original Article from http://www.strathweb.com/2012/05/implementing-message-handlers-to-track-your-asp-net-web-api-usage/

Today’s focus is going to be on message handlers (or, to be precise, DelegatingHandlers) in ASP.NET Web API. If you are familiar with WCF you can surely recall them – used to be called DelegatingChannels at some point – but the purpose has been the same all along, to provide the first (or last, depending whether you look at requests or responses) extendibility point in your Web API applications. You stack up as many message handlers on top of each other as you wish, and the request will travel through all of them.
This, in turn, gives us developers a possibility to process/alter/modify/decline the incoming HTTP request before it reaches the HttpControllerDispatcher. Then, when the controller creates the response, it goes through the same chain of message handlers again, so we can tamper with the response. One example of the applicability of this is that message handlers are a perfect place to address security related matters i.e. integrating OAuth.
The plan for today is to show how DelegatingHandlers are used by building a functionality that checks for an API key on an incoming API request and then logs all requests and responses, thus allowing you to track the usage of your API.

What are we going to do?

We are going to implement two DelegatingHandlers.
1. First, will deal with API key checking. Since we are going to use API Keys to log API usage, every request needs to include an API key, and this handler will ensure it. If no key is provided, the requests will not be processed further
2. Then we will build a second DelegatingHandler, which will capture all request and response data flowing in and out of ApiControllers and log them into a repository. From there, they can be viewed by Admin user.

Models

Let’s start by declaring our models first. This way later on, we can solely focus on Web API specific stuff.
We will have to deal with two types of items – HttpRequestMessage and HttpResponseMessage. Therefore I’m going to set up a base class for all the common properties and two inheriting classes. We’re gonna use primitive types all across the board (i.e. Dictionary instead of HttpHeaders collection, integer instead of StatusCode etc) so that we can easily serialize our objects later.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class WebApiUsage
{
public int id { get; set; }
public string ApiKey { get; set; }
public Datetime Timestamp { get; set; }
public string UsageType { get; set; }
public string Content { get; set; }
public Dictionary<string, string> Headers { get; set; }
protected void extractHeaders(HttpHeaders h)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (var i in h.ToList())
{
if (i.Value != null)
{
string header = string.Empty;
foreach (var j in i.Value)
{
header += j + " ";
}
dict.Add(i.Key, header);
}
}
Headers = dict;
}
}
There is not much exciting stuff here – several properties that can be associated with both requests and responses:
– ID
– ApiKey – so that we can associate the API interaction with a given consumer
– Timestamp – when the interaction happen
– UsageType – which will indicate whether we deal with a Request or Response
– Content – the content of the Request or Response
– Headers – containing headers as key-value string/string pairs
Additionally we include a method callabale from inheriting classes to extract Headers information from HttpHeaders object to a readable and serializable dictionary.
Next, let’s design our derived classes. First Request:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class WebApiUsageRequest : WebApiUsage
{
public string Uri { get; set; }
public string RequestMethod { get; set; }
public string IP { get; set; }
public WebApiUsageRequest(HttpRequestMessage request, string apikey)
{
if (request != null)
{
UsageType = request.GetType().Name;
RequestMethod = request.Method.Method;
Uri = request.RequestUri.ToString();
IP = ((HttpContextBase)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
ApiKey = apikey;
    Datetime = Datetime.Now;
base.extractHeaders(request.Headers);
}
else
{
throw new ArgumentNullException("request cannot be null");
}
}
}
We introduce three additional properties here, specific for Requests only:
– Uri – what has been requested
– RequestMethod – GET, POST, PUT,
– IP – from which IP has the request been issued
The constructor will take an HttpRequestMessage object and the API key string.
The response model looks like this:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class WebApiUsageResponse : WebApiUsage
{
public int StatusCode { get; set; }
public WebApiUsageResponse(HttpResponseMessage response, string apikey)
{
if (response != null)
{
UsageType = response.GetType().Name;
StatusCode = Convert.ToInt32(response.StatusCode);
base.extractHeaders(response.Headers);
   Datetime = Datetime.Now;
ApiKey = apikey;
}
else
{
throw new ArgumentNullException("response cannot be null");
}
}
}
This one, in turn, has just one type-specific proeprty, to hold the StatusCode of the response. The constructor takes an HttpResponseMessage object and the API key string.
Now, before we can say that the models are ready, we need to decorate them with some Serialization attributes. This is necessary since System.Runtime.Serialization doesn’t automatically click with inherited objects. Below is the complete code after the modifciations:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
[DataContract]
[KnownType(typeof(WebApiUsageRequest))]
[KnownType(typeof(WebApiUsageResponse))]
public class WebApiUsage
{
[DataMember]
public int id { get; set; }
[DataMember]
public string ApiKey { get; set; }
[DataMember]
public Datetime Timestamp { get; set; }
[DataMember]
public string UsageType { get; set; }
[DataMember]
public string Content { get; set; }
[DataMember]
public Dictionary<string, string> Headers { get; set; }
protected void extractHeaders(HttpHeaders h)
{
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (var i in h.ToList())
{
if (i.Value != null)
{
string header = string.Empty;
foreach (var j in i.Value)
{
header += j + " ";
}
dict.Add(i.Key, header);
}
}
Headers = dict;
}
}
[DataContract]
public class WebApiUsageRequest : WebApiUsage
{
[DataMember]
public string Uri { get; set; }
[DataMember]
public string RequestMethod { get; set; }
[DataMember]
public string IP { get; set; }
public WebApiUsageRequest(HttpRequestMessage request, string apikey)
{
if (request != null)
{
UsageType = request.GetType().Name;
RequestMethod = request.Method.Method;
Uri = request.RequestUri.ToString();
IP = ((HttpContextBase)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
ApiKey = apikey;
        Timestamp = Datetime.Now;
base.extractHeaders(request.Headers);
}
else
{
throw new ArgumentNullException("request cannot be null");
}
}
}
[DataContract]
public class WebApiUsageResponse : WebApiUsage
{
[DataMember]
public int StatusCode { get; set; }
public WebApiUsageResponse(HttpResponseMessage response, string apikey)
{
if (response != null)
{
UsageType = response.GetType().Name;
StatusCode = Convert.ToInt32(response.StatusCode);
base.extractHeaders(response.Headers);
   Timestamp = Datetime.Now;
ApiKey = apikey;
}
else
{
throw new ArgumentNullException("response cannot be null");
}
}
}



Implementing a simple repository

Now, let’s implement a simple repository to store our logged API usage. I will not play with the database here, so I’m going to dump everything into a static property which can be accessed for testing purposes. Obviously in a normal applciation you’d replace it with some data storage solution.
Interface:
C#
1
2
3
4
5
6
7
public interface IApiUsageRepository
{
IEnumerable<WebApiUsage> GetAll();
IEnumerable<WebApiUsage> GetAll(string key);
WebApiUsage Get(int id);
WebApiUsage Add(WebApiUsage au);
}
And the class implementation:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ApiUsageRepository : IApiUsageRepository
{
private int _nextId = 1;
private static ConcurrentQueue<WebApiUsage> _aus = new ConcurrentQueue<WebApiUsage>();
public IEnumerable<WebApiUsage> GetAll()
{
return _aus.AsQueryable();
}
public WebApiUsage Get(int id)
{
return _aus.ToList().Find(i => i.id == id);
}
public IEnumerable<WebApiUsage> GetAll(string key)
{
return _aus.ToList().FindAll(i => i.ApiKey == key);
}
public WebApiUsage Add(WebApiUsage aus)
{
aus.id = _nextId++;
_aus.Enqueue(aus);
return aus;
}
}





As mentioned, the static instance of ConcurrentQueue will be our data repository for this exercise.

Creating the DelegatingHandlers

First let’s do the API key Handlers. As explained earlier, it’s sole purpose is to check if the request came in with an Apikey – if yes, we continue, if not we return an error to the client. Of course this is the proper place to introduce any additional key verification (i.e. matching the allowed keys and so on), but for simplicity we are not going to do that. A good reference (albeit WCF specific) can be found here in Pablo’s post.
We process the request by writing a new class inheriting from System.Net.Http.DelegatingHandler class and overriding its SendAsync method.
C#
1
2
3
4
5
6
7
8
9
10
11
12
public class WebApiKeyHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string apikey = HttpUtility.ParseQueryString(request.RequestUri.Query).Get("apikey");
if (string.IsNullOrWhiteSpace(apikey)) {
HttpResponseMessage response = request.CreateErrorResponse(HttpStatusCode.Forbidden, "You can't use the API without the key.");
throw new HttpResponseException(response);
} else {
return base.SendAsync(request, cancellationToken);
}
}
The handler intercepts the requests, and checks for API Key. We are using the new (introduced just last week to the source of ASP.NET Web API) , content-negotiated mechanism of returning a menaingful Error to the client through request through HttpRequestMessage. CreateErrorResponse() method.
If for some reason you can’t get this latest source to work you can create the error accordingly instead (albeit that’s not content negotiated) – up to you.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string apikey = HttpUtility.ParseQueryString(request.RequestUri.Query).Get("apikey");
if (string.IsNullOrWhiteSpace(apikey)) {
return SendError("You can't use the API without the key.", HttpStatusCode.Forbidden);
} else {
return base.SendAsync(request, cancellationToken);
}
}
private Task<HttpResponseMessage> SendError(string error, HttpStatusCode code)
{
var response = new HttpResponseMessage();
response.Content = new StringContent(error);
response.StatusCode = code;
return Task<HttpResponseMessage>.Factory.StartNew(() => response);
}







If you try to run the application now and make any ApiController request, you’d see that you get an error.

That’s because from now, any request needs to come in with ?apikey=XXX in the querysrting.

Wiring the Api Usage Handler

This is going to be surprisingly easy. We have the Models ready, we have the repository ready, and we have the first handler in place. We start off with the class dervied from System.Net.Http.DelegatingHandler, as before, and a private instance of the repo.
C#
1
2
3
4
5
6
7
8
9
public class WebApiUsageHandler : DelegatingHandler
{
private static readonly IApiUsageRepository _repo = new ApiUsageRepository();
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
//stuff happens here
}
}








Now we just add the following:
– upon arrival of the request, we create a new instance of our WebApiUsageRequest, read asynchronously the Request’s body and add the item to the repo
– then we continue with the normal flow of the events (meaning the request is send back along the ASP.NET Web API pipeline)
– finally we intercept the Response, instantiate our WebApiUsageResponse and add that to the repo as well
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class WebApiUsageHandler : DelegatingHandler
{
private static readonly IApiUsageRepository _repo = new ApiUsageRepository();
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string apikey = HttpUtility.ParseQueryString(request.RequestUri.Query).Get("apikey");
var apiRequest = new WebApiUsageRequest(request, apikey);
request.Content.ReadAsStringAsync().ContinueWith(t =>
{
apiRequest.Content = t.Result;
_repo.Add(apiRequest);
});
return base.SendAsync(request, cancellationToken).ContinueWith(
task =>
{
var apiResponse = new WebApiUsageResponse(task.Result, apikey);
apiResponse.Content = task.Result.Content.ReadAsStringAsync().Result;
_repo.Add(apiResponse);
return task.Result;
}
);
}
}









This was fairly easy, wasn’t it?
Now we just need to register our DelegatingHandlers in the global.asax, inside Application_Start().
C#
1
2
GlobalConfiguration.Configuration.MessageHandlers.Add(new WebApiUsageHandler());
GlobalConfiguration.Configuration.MessageHandlers.Add(new WebApiKeyHandler());
The important thing to remember is the order. Last added handler gets called first.

Adding a controller to view usage data

Now, just for the pure ability to test what we have done, let’s add a controller which will expose all the usage data.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class AdminController : ApiController
{
private IApiUsageRepository _usage;
public AdminController()
{
_usage = new ApiUsageRepository();
}
public IEnumerable<WebApiUsage> getAll()
{
return _usage.GetAll();
}
public WebApiUsage get(string key)
{
return _usage.Get(key);
}
}











We can use this controller to grab the data of API usage. Notice that since we decorated our Models carefully with appropriate serialization attributes, we can just safely return our Models (no DTO or anything like that needed).

Trying it

Let’s fire up the browser and make a few requests:
– http://localhost:50656/api/values/?apikey=testkey
– http://localhost:50656/api/values/1?apikey=differentkey
– http://localhost:50656/api/values/2?apikey=testkey
And now go to http://localhost:50656/api/admin/?apikey=adminkey to view everything that has been logged. (Note: even this request needs to come with a key!).

As you can see everything comes out nicely in JSON format (IP is showing like this since it’s running off localhost).
We can use the other method of the repository, to get all usage data for a specific key i.e. “differentkey” – in this case we navigate to http://localhost:50656/api/admin/?key=differentkey&apikey=adminkey

Finally, we can just pull one of the entries by ID – i.e.

Summary and source

Message handlers can be extremely useful and powerful tools.

Tuesday, November 15, 2011

Creating a Tag Cloud in ASP.NET


In the following article you'll find the method to create Tag Cloud in ASP.Net,



This article is

By Scott Mitchell





Introduction


tag cloud is a way to display a weighted list such that the weight of each item is reflected by the size of the item's text. Tag clouds provide a quick way for one to eyeball a list and ascertain what items are more prevalent. Oftentimes, each item in a tag cloud is rendered as a link that, when clicked, allows the user to drill into the selected category. For example, given any parent/child relationship in a database, we may be interested in seeing how many children each parent has, relative to one another. The following image of a tag cloud lists the categories in the Northwind database, with the size of each item is proportional to the number of products for each category, relative to the other categories. (Each category name, if clicked, takes the user to a page that lists the products for that particular category.)


A tag cloud.
Tag clouds are commonly used in websites that support tagging. Tagging is a technique of assigning a set of string values to a particular item - such as classifying a picture of your pet dog at a photo sharing website with string tags like "dog", "pet", "adorable", and so on. Tags provide an informal way for users to easily classify content and make it easy to visualize the most common tags and to drill down into a specific tag. However, tag clouds are not limited to websites that support tagging and can be used to offer an alternative view of a weighted list (such as parent/child data in a database).
In this article we'll examine how to build a tag cloud in ASP.NET. In this article we'll focus on accomplishing this through code in an ASP.NET page's code-behind class. In a future article, we'll move this code out of the ASP.NET page and into a stand alone, custom, compiled server control that supports data binding, use of declarative data source controls, and so on. Read on to learn more!

Deciding on the Tag Cloud's Font Sizing


When designing a tag cloud, it is important to first determine how the font sizes will vary by item. The font sizes can be specified using relative font sizes - xx-small, medium, x-large, and so on - or by absolute font sizes - 12pt, 32pt, etc. The benefit of using relative font sizes is that the fonts will scale based on a user's browser's text size settings. Another design decision to make is the spectrum of font sizes. That is, how many distinct font sizes are allowed? For the code we'll examine shortly, I've decided to use seven absolute font sizes: xx-small, x-small, small, medium, large, x-large, xx-large.Another vital design decision is how the font sizing is selected based on the distribution of the weights. For my code, I've decided to use a simple linear distribution. If the weighted list ranges from a minimum value of, say, 60, to a maximum value of 200, then I break down each of the seven font sizes into ranges plotted linearly along the minima and maxima. In this example, the delta is 140 (200 - 60). Divided by 7 results in each font size having a range of 20 units. So for any list items whose weight is between 60 and 80, I use font size xx-small; for those between 80 and 100, I use x-small; and so on.
While this linear scale is simple to implement and works well for evenly distributed data points, if you have skewed data points you'll end up with potentially extreme results. Consider the case where the weighted list being displayed has one data point with a weight of 60 (our minimum) and five data points between weights 180 and 200. The result is that the first data point will be displayed with the smallest font size (xx-small) and all remaining five will be displayed in the largest font size (xx-large). But this doesn't show the variation between the five in the 180-200 range. To capture this, an alternative model is to base the font sizes on the standard deviation of the distribution, which captures how far each data point deviates from the mean (the average). For more on this, check out Cloud Control for ASP.NET. It's an open source tag cloud control for ASP.NET created by Rama Krishna Vavilala that uses the standard deviation model.

Building the Cloud


Ideally, a tag cloud could be associated with some data, a few properties set, and, voila, the tag cloud appears! In fact, we'll examine how to accomplish exactly this in a future article by creating a custom, compiled ASP.NET 2.0 server control. For now, though, let's just implement the tag cloud directly from an ASP.NET page (although this could be moved to a User Control for greater reuse opportunities).First things first - we need the data that returns the list with each item weighted. In the demo downloadable at the end of this article, I have used a SqlDataSource control to query the Northwind database, returning the CategoryIDCategoryName, and number of products belonging to each category:


SELECT Categories.CategoryID, Categories.CategoryName, 
       COUNT(Products.ProductID) AS NumberOfProducts 

FROM Categories 
    INNER JOIN Products ON 
        Categories.CategoryID = Products.CategoryID 

GROUP BY Categories.CategoryID, Categories.CategoryName
ORDER BY Categories.CategoryName

This query uses the GROUP BY clause to return the count of products associated with each category. See Using the GROUP BY Clause for more information on this SQL clause.
The tag cloud is outputted in the Web page via a Literal Web control named CloudMarkup. In code we're going to loop through the database results, compute the font size scale, and then emit an HTML hyperlink as markup into the Text property of the Literal control. To start, we need to get the data from the SqlDataSource control. This is accomplished by calling its Select() method, which returns a DataView object:

'First, read data from SqlDataSource
Dim cloudData As DataView = CType(CategoriesProductsBreakdownDataSource.Select(DataSourceSelectArguments.Empty), DataView)

Next, a series of constants are defined in an attempt to generalize this code at least a little bit. For example, there are constants that define the names of the database columns that return the weight, the text field to display, along with the field to use (and a format string) when constructing the URL for each hyperlink. You'll also find the set of font sizes and the markup to inject between each link.

Const SpacerMarkup As String = " " 'The markup injected between each item in the cloud
Dim FontScale() As String = {"xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"}

'All database column names are centralized here. To customize this, simply modify the column names here
Const WeightColumnName As String = "NumberOfProducts"
Const TextColumnName As String = "CategoryName"
Const NavigateUrlColumnName As String = "CategoryID"
Const NavigateUrlFormatString As String = "~/ViewProductsByCategory.aspx?CategoryID={0}"

Next, we need to determine the minimum and maximum weight values in the list. This information is then used to compute the linear scale by which we'll map an item's weight to a font size. ThescaleUnitLength holds the "length" of each notch on the scale.

Dim minWeight As Decimal = Decimal.MaxValue, maxWeight As Decimal = Decimal.MinValue

For Each row As DataRowView In cloudData
    Dim numProductsObj As Object = row(WeightColumnName)
    If Not Convert.IsDBNull(numProductsObj) Then
       Dim numProductsDec As Decimal = Convert.ToDecimal(numProductsObj)

       If numProductsDec < minWeight Then minWeight = numProductsDec
       If numProductsDec > maxWeight Then maxWeight = numProductsDec
    End If
Next

Dim scaleUnitLength As Decimal = (maxWeight - minWeight + 1) / Convert.ToDecimal(FontScale.Length)

After computing the scale, the data is enumerated one more time, this time with a hyperlink (<a>) element emitted for each record. To find the place on the scale, the current item's weight is subtracted from the minimum and divided by scaleUnitLength. This index is used to select the appropriate font size from FontScale. Also note that the specified values for NavigateUrlColumnName andNavigateUrlFormatString are used to configure the href portion of the hyperlink.

For Each row As DataRowView In cloudData
    Dim numProductsObj As Object = row("NumberOfProducts")
    If Not Convert.IsDBNull(numProductsObj) Then
       Dim numProductsDec As Decimal = Convert.ToDecimal(numProductsObj)

       Dim scaleValue As Integer = Math.Truncate((numProductsDec - minWeight) / scaleUnitLength)
       CloudMarkup.Text &= String.Format("<a href=""{0}"" style=""font-size:{1};"">{2}</a>{3}", _
                                    Page.ResolveUrl(String.Format(NavigateUrlFormatString, row(NavigateUrlColumnName).ToString())), _
                                    FontScale(scaleValue), row(TextColumnName).ToString(), SpacerMarkup)
    End If
Next

That's all there is to it! The resulting output is a chunk of HTML that, when rendered in the user's browser, lists each category as a hyperlink pointing to ViewProductsByCategory.aspx?CategoryID=categoryID. Each link's text size is based on its weight using a linear scale. The following screenshot below shows a tag cloud of the Northwind database's categories table along with the raw data used to populate the cloud.



A tag cloud along with the raw data.


Conclusion


Tag clouds can provide an alternative means for displaying a weighted list. As we saw in this article, they can be implemented with just a bit of code (although the standard deviation approach takes a bit more effort), and offer visual cues and a way to quickly drill into the details of any item. In a future article we'll look at how to move this logic to a custom, compiled ASP.NET 2.0 server control. Until then.....Happy Programming!

MVC Introduction


ASP.NET MVC Overview (C#)

The Model-View-Controller (MVC) architectural pattern separates an application into three main components: the model, the view, and the controller. The ASP.NET MVC framework provides an alternative to the ASP.NET Web Forms pattern for creating MVC-based Web applications. The ASP.NET MVC framework is a lightweight, highly testable presentation framework that (as with Web Forms-based applications) is integrated with existing ASP.NET features, such as master pages and membership-based authentication. The MVC framework is defined in theSystem.Web.Mvc namespace and is a fundamental, supported part of the System.Web namespace.

MVC is a standard design pattern that many developers are familiar with. Some types of Web applications will benefit from the MVC framework. Others will continue to use the traditional ASP.NET application pattern that is based on Web Forms and postbacks. Other types of Web applications will combine the two approaches; neither approach excludes the other.

The MVC framework includes the following components:
Invoking a controller action that expects a parameter value
Figure 01: Invoking a controller action that expects a parameter value (Click to view full-size image)
  • Models. Model objects are the parts of the application that implement the logic for the application s data domain. Often, model objects retrieve and store model state in a database. For example, a Product object might retrieve information from a database, operate on it, and then write updated information back to a Products table in SQL Server.

In small applications, the model is often a conceptual separation instead of a physical one. For example, if the application only reads a data set and sends it to the view, the application does not have a physical model layer and associated classes. In that case, the data set takes on the role of a model object.
  • Views. Views are the components that display the application s user interface (UI). Typically, this UI is created from the model data. An example would be an edit view of a Products table that displays text boxes, drop-down lists, and check boxes based on the current state of a Products object.

  • Controllers. Controllers are the components that handle user interaction, work with the model, and ultimately select a view to render that displays UI. In an MVC application, the view only displays information; the controller handles and responds to user input and interaction. For example, the controller handles query-string values, and passes these values to the model, which in turn queries the database by using the values.

The MVC pattern helps you create applications that separate the different aspects of the application (input logic, business logic, and UI logic), while providing a loose coupling between these elements. The pattern specifies where each kind of logic should be located in the application. The UI logic belongs in the view. Input logic belongs in the controller. Business logic belongs in the model. This separation helps you manage complexity when you build an application, because it enables you to focus on one aspect of the implementation at a time. For example, you can focus on the view without depending on the business logic.

In addition to managing complexity, the MVC pattern makes it easier to test applications than it is to test a Web Forms-based ASP.NET Web application. For example, in a Web Forms-based ASP.NET Web application, a single class is used both to display output and to respond to user input. Writing automated tests for Web Forms-based ASP.NET applications can be complex, because to test an individual page, you must instantiate the page class, all its child controls, and additional dependent classes in the application. Because so many classes are instantiated to run the page, it can be hard to write tests that focus exclusively on individual parts of the application. Tests for Web Forms-based ASP.NET applications can therefore be more difficult to implement than tests in an MVC application. Moreover, tests in a Web Forms-based ASP.NET application require a Web server. The MVC framework decouples the components and makes heavy use of interfaces, which makes it possible to test individual components in isolation from the rest of the framework.

The loose coupling between the three main components of an MVC application also promotes parallel development. For instance, one developer can work on the view, a second developer can work on the controller logic, and a third developer can focus on the business logic in the model.

Deciding When to Create an MVC Application

You must consider carefully whether to implement a Web application by using either the ASP.NET MVC framework or the ASP.NET Web Forms model. The MVC framework does not replace the Web Forms model; you can use either framework for Web applications. (If you have existing Web Forms-based applications, these continue to work exactly as they always have.)

Before you decide to use the MVC framework or the Web Forms model for a specific Web site, weigh the advantages of each approach.

Advantages of an MVC-Based Web Application

The ASP.NET MVC framework offers the following advantages:
  • It makes it easier to manage complexity by dividing an application into the model, the view, and the controller.
  • It does not use view state or server-based forms. This makes the MVC framework ideal for developers who want full control over the behavior of an application.
  • It uses a Front Controller pattern that processes Web application requests through a single controller. This enables you to design an application that supports a rich routing infrastructure. For more information, seeFront Controller on the MSDN Web site.
  • It provides better support for test-driven development (TDD).
  • It works well for Web applications that are supported by large teams of developers and Web designers who need a high degree of control over the application behavior.

Advantages of a Web Forms-Based Web Application

The Web Forms-based framework offers the following advantages:
  • It supports an event model that preserves state over HTTP, which benefits line-of-business Web application development. The Web Forms-based application provides dozens of events that are supported in hundreds of server controls.
  • It uses a Page Controller pattern that adds functionality to individual pages. For more information, see Page Controller on the MSDN Web site.
  • It uses view state or server-based forms, which can make managing state information easier.
  • It works well for small teams of Web developers and designers who want to take advantage of the large number of components available for rapid application development.
  • In general, it is less complex for application development, because the components (the Page class, controls, and so on) are tightly integrated and usually require less code than the MVC model.

Features of the ASP.NET MVC Framework

The ASP.NET MVC framework provides the following features:
  • Separation of application tasks (input logic, business logic, and UI logic), testability, and test-driven development (TDD) by default. All core contracts in the MVC framework are interface-based and can be tested by using mock objects, which are simulated objects that imitate the behavior of actual objects in the application. You can unit-test the application without having to run the controllers in an ASP.NET process, which makes unit testing fast and flexible. You can use any unit-testing framework that is compatible with the .NET Framework.
  • An extensible and pluggable framework. The components of the ASP.NET MVC framework are designed so that they can be easily replaced or customized. You can plug in your own view engine, URL routing policy, action-method parameter serialization, and other components. The ASP.NET MVC framework also supports the use of Dependency Injection (DI) and Inversion of Control (IOC) container models. DI allows you to inject objects into a class, instead of relying on the class to create the object itself. IOC specifies that if an object requires another object, the first objects should get the second object from an outside source such as a configuration file. This makes testing easier.
  • A powerful URL-mapping component that lets you build applications that have comprehensible and searchable URLs. URLs do not have to include file-name extensions, and are designed to support URL naming patterns that work well for search engine optimization (SEO) and representational state transfer (REST) addressing.
  • Support for using the markup in existing ASP.NET page (.aspx files), user control (.ascx files), and master page (.master files) markup files as view templates. You can use existing ASP.NET features with the ASP.NET MVC framework, such as nested master pages, in-line expressions (<%= %>), declarative server controls, templates, data-binding, localization, and so on.
  • Support for existing ASP.NET features. ASP.NET MVC lets you use features such as forms authentication and Windows authentication, URL authorization, membership and roles, output and data caching, session and profile state management, health monitoring, the configuration system, and the provider architecture.
Microsoft
By Microsoft

Friday, June 17, 2011


Configuration de Microsoft Active Directory  en vue de personnaliser l'affichage Activation de l'attribut PreferredLanguage 


NB : Procédure s'applique à Windows 2000 

Avant de commencer

Active Directory doit être installé et configuré avant l'installation de WebSphere Everyplace Access.
Remarque : Si vous exécutez Microsoft Active Directory, vous ne pouvez pas utiliser WebSphere Portal pour créer des utilisateurs et des groupes sauf si vous configurez WebSphere Application Server pour utiliser LDAP via SSL. Pour plus d'informations, voir Sécurisation des registres d'utilisateurs.

Exemple de structure Active Directory

Le schéma suivant est un exemple de structure Active Directory et il est référencé tout au long de la documentation par souci de cohérence. L'exemple ci-dessous a pour objet de vous aider à déterminer les valeurs appropriées lorsque vous configurez WebSphere Portal de façon à ce qu'il fonctionne avec la structure spécifique de votre annuaire. Les valeurs indiquées correspondent aux valeurs par défaut de ce LDAP. Si vous utilisez un schéma existant qui diffère de cet exemple, remplacez les valeurs de l'exemple par vos valeurs. La valeur "cn" correspond par exemple au préfixe du groupe ; remplacez-le par le préfixe de groupe correspondant à votre schéma.
  • suffixe LDAP="dc=votresociete,dc=com"
  • préfixe utilisateur="cn"
  • suffixe utilisateur="cn=users"
  • préfixe groupe="cn"
  • suffixe groupe="cn=utilisateurs"
  • DN administrateur portail="cn=wpsadmin,cn=utilisateurs,dc=votresociete,dc=com"
  • groupe administrateur portail="cn=wpsadmins,cn=utilisateurs,dc=votresociete,dc=com"

Création d'un utilisateur comme administrateur WebSphere Everyplace Access

Si l'utilisateur administrateur WebSphere Everyplace Access n'existe pas dans l'annuaire, procédez comme suit .
  1. Utilisez les outils d'administration Windows pour créer un nouvel utilisateur qui sera le premier utilisateur administrateur WebSphere Everyplace Access.
  2. Définissez le mot de passe du nouvel utilisateur administrateur WebSphere Everyplace Access créé.
  3. Activez le compte de l'administrateur WebSphere Everyplace Access à l'aide des outils d'administration Windows.

Modification du schéma Active Directory (facultatif)

Remarque : Cette procédure ne s'applique qu'à Windows 2000 et n'est pas nécessaire sous Windows 2003.
L'attribut preferredLanguage (langue préférée) peut être ajouté au schéma Active Directory pour créer et modifier des utilisateurs de portail. L'ajout de cet attribut permet aux utilisateurs de définir leur "langue préférée" pour que le contenu du portail apparaisse dans leur langue lorsqu'ils se connecteront à celui-ci. Dans le cas contraire, les pages du portail apparaissent dans la langue définie dans les paramètres du navigateur. Pour ajouter l'attribut preferredLanguageà Active Directory, procédez comme suit.
  1. Si vous n'avez pas installé les outils de support Windows 2000, installez-les à partir du répertoire \SUPPORT\TOOLS du CD d'installation de Windows 2000.
  2. Enregistrez le fichier schmmgmt.dll. Entrez par exemple la chaîne suivante à partir d'une ligne de commande : regsvr32 schmmgmt.dll
  3. Ajoutez le snap-in du schéma Active Directory en procédant comme suit :
    1. Chargez la console Outils d'administration de la sécurité. Dans le menu Démarrer de Windows, sélectionnez Programmes > Outils de support de Windows 2000 > Outils > Outils d'administration de la sécurité
    2. Sélectionnez Console > Ajouter/Supprimer un composant logiciel enfichable.
    3. Dans l'onglet Autonome, cliquez sur Ajouter.
    4. Sélectionnez Schéma Active Directory dans la liste Composants logiciels enfichables disponibles.
    5. Cliquez sur Ajouter pour ajouter le snap-in à la console.
  4. Configurez le snap-in du schéma Active Directory en procédant comme suit :
    1. Dans la console des outils d'administration de la sécurité, cliquez à l'aide du bouton droit de la souris sur Schéma Active Directory, puis sélectionnez Maître d'opérations.
    2. Sélectionnez Le schéma peut être modifié sur ce contrôleur de domaine, puis cliquez sur OK pour enregistrer cette modification.
  5. Créez l'attribut preferredLanguage.
    1. Dans la console des outils d'administration de la sécurité, développez Schéma Active Directory > Attributs.
    2. Cliquez à l'aide du bouton droit de la souris sur Attributs, puis sélectionnez Créer un attribut.
    3. Cliquez sur Continuer pour accéder aux propriétés du nouvel attribut.
    4. Entrez les valeurs suivantes dans Créer un nouvel attribut :
      Nom de la zoneValeur
      Nom communpreferredLanguage
      Nom LDAP affichépreferredLanguage
      ID objet X.500 unique2.16.840.1.113730.3.1.39
      SyntaxeChaîne ne prenant pas en compte la distinction majuscules/minuscules
    5. Cliquez sur OK pour créer l'attribut preferredLanguage.
  6. Pour ajouter l'attribut preferredLanguage à la classe d'objets utilisateur, procédez comme suit :
    1. Dans la console des outils d'administration de la sécurité, développez Schéma Active Directory > Classes.
    2. Cliquez deux fois sur user pour ouvrir les propriétés utilisateur.
    3. Sélectionnez l'onglet Attributs.
    4. Dans la section Facultatif, cliquez sur Ajouter pour ajouter un nouvel objet de schéma.
    5. Sélectionnez preferredLanguage dans la liste d'objets, puis cliquez sur OK pour ajouter cet objet.