Вы находитесь на странице: 1из 39

Microsoft Official Course

Module 4

Extending and Securing ASP.NET


Web API Services
Module Overview

The ASP.NET Web API Pipeline


Creating OData Services
Implementing Security in ASP.NET Web API
Services
Injecting Dependencies into Controllers
Lesson 1: The ASP.NET Web API Pipeline

ASP.NET Web API Processing Architecture


The DelegatingHandler Class
Filters
Demonstration: The Flow of Requests and
Responses Through the Pipeline
Asynchronous Actions
Demonstration: Creating Asynchronous Actions
Media Type Formatters
Demonstration: Returning Images by Using Media
Type Formatters
ASP.NET Web API Processing Architecture

Self Hosting HttpServer ApiController

HttpSelfHostServer MessageHandler Action

ApiControllerActionInvo
MessageHandler
ker

IIS
Action Filters

HttpControllerHandler
HttpRoutingDispatcher HttpActionBinding

HttpControllerDispatcher Authorization Filters

Error Filters
The DelegatingHandler Class

Message handlers are objects that perform pre-


processing on a message
Derive from the HttpMessageHandler class
Receive an HttpRequestMessage
Return an HttpResponseMessage

Usually chained in a pipeline where every handler


has an internal handler it calls
Derive from the DelegatingHandler class to
implement chaining and to extend the ASP.NET
Web API message handlers pipeline
Model Binders

Action parameters are initialized by:


Routing templates. Extract values from the URI path.
Model binders. Parse query strings
Formatters. Deserialize the message body.
Built-in model binders are capable of parsing primitive,
collection, and complex types
Create custom model binders for specific scenarios:
Set value of two parameters from a single query string value
Set a complex object by mixing query string and body content
To create a custom model binder, implement the
IModelBinder interface
Apply the new binder to the parameter with the
[ModelBinder] attribute
Filters

Filters provide a mechanism to extend the pipeline


for specific actions or controllers
Filters provides a mechanism similar to delegating
handlers
Among the common filters are:
Exception filters
Authorization filters
Action filters
Demonstration: The Flow of Requests and
Responses Through the Pipeline

In this demonstration you will see how to:


Create and configure a Message Handler
Create and configure an Action Filter
Asynchronous Actions

One of the most common tasks for services is to


perform I/O calls (network, disk, database)
By using the synchronous I/O calls, the executing
thread is blocked

public string Get()


{
var client = WebRequest.Create("http://.../");
var response = client.GetResponse();
var stream = response.GetResponseStream();
var reader = new StreamReader(stream);
return reader.ReadToEnd();
}
Asynchronous Actions

While simple to implement, synchronous code


needlessly blocks the actions thread
ASP.NET Web API in combination with the async
and await keywords, provides a better way to
write asynchronous code:

public async Task<string> Get()


{
var client = new HttpClient();
var response = await client.GetAsync("http://...");
return await response.Content.ReadAsStringAsync();
}
Demonstration: Creating Asynchronous Actions

In this demonstration, you will see how to convert


synchronous actions to asynchronous actions by
using the async and await keywords
Media Type Formatters

Media type formatters provide a mechanism for


content-negotiation
ASP.NET Web API has built-in support for three
media types:
XML
JSON
Form-urlencoded (HTML forms)

To handle other media types, create custom media


type formatters
Derive from the MediaTypeFormatter abstract
class and implement your logic for reading/writing
Configuring the Content Type for the Media
Formatter
public AgentCSVFormatter()
{
this.SupportedMediaTypes.Add(
new MediaTypeHeaderValue("text/csv"));
}

public override bool CanWriteType(Type type)


{
Type enumerableType =
typeof(IEnumerable<Employee>);
return enumerableType.IsAssignableFrom(type);
}
Implementing the WriteToStream method

public override void WriteToStream(Type type, object value,


Stream writeStream, System.Net.Http.HttpContent content)
{
var employees = value as IEnumerable<Employee>;
using (var writer = new StreamWriter(writeStream))
{
writer.WriteLine("Name, ID"); // Write CSV header
foreach (var employee in employees)
{
writer.WriteLine("{0},{1}", employee.Name,employee.ID);
}
}
}
Demonstration: Returning Images by Using
Media Type Formatters

In this demonstration, you will see how to use


custom media type formatters
Lesson 2: Creating OData Services

OData Queryable Actions


OData Models
Consuming OData Services
Demonstration: Creating and Consuming an
OData Services
OData Queryable Actions

The Open Data Protocol (OData) provides a


RESTful standard for exposing data models
OData uses URIs to perform query operations:
Entity projection $select
Sorting $orderby
Entity sub-setting $top,$skip
Filtering $filter, logical operators: eq, ne, gt, lt
Defining OData Actions

To support OData queries, define an action with


the following characteristics:
Returns IQueryable<T> or IEnumerable<T>
Decorated with the [Queryable] attribute

[Queryable]
public IQueryable<Course> Get()
{
}
OData Models

OData also provides a mechanism for exposing


entity models:
Publishing the models metadata
Exposing relations between entities using the Atom
media type

GET http://localhost/api/odata/$metadata

GET http://localhost/api/odata/Flights

PUT http://localhost/api/odata/Flights(123)
Creating and Exposing OData Models

Exposing an OData model requires the following


configuration:
Creating an EDM model using the
ODataConventionModelBuilder class
Adding a route using the MapODataRoute method

In addition, any controller exposed in the model


should derive from the ODataController or
EntitySetController<TEntity, TKey> classes
Consuming OData Services

Use the Add Service Reference dialog box in


Visual Studio to add a reference to the OData
service
Generates client-side code
All the entity types exposed by the Odata service
An OData proxy class called Container

Use LINQ to query the OData service


var container = new Container(new Uri(""));
var course = (from c in container.Courses
where c.Code == "20487"
select c).Single();
Demonstration: Creating and Consuming an
OData Services

In this demonstration, you will see how to:


Create queryable actions in ASP.NET Web API
Create OData controllers
Consuming OData services using Visual Studio
2012
Lesson 3: Implementing Security in ASP.NET
Web API Services

Securing HTTP with HTTPS


Authenticating Clients
Authorizing Clients
Demonstration: Creating Secured ASP.NET Web
API Services
Securing HTTP with HTTPS

Securing communication is achieved by using


HTTPS with SSL (Secure Socket Layer)
Provides an encrypted communication channel
Managed by IIS, no need to change the code
Requires a server certificate
SSL handshake supports client certificate authentication
Does not handle client authorization
How SSL Works

3. Client verifies the


servers certificate

1. Client requests a secured session

2. Server responds with an X.509 certificate

4. Client sends a symmetric encryption key


(encrypted with the servers public key)

6. Client and server exchange encrypted messages


(encrypted with the symmetric key)

5. Server decrypts the


encryption key with its
private key
Authenticating Clients

Authenticating a client means verifying its identity


Who is responsible for the authentication?
IIS
ASP.NET
You
Someone else?

IIS can authenticate users and prevent access by


unidentified users
Configured in IIS
Supports several credential types (username/password,
windows identity, certificate)
Easiest way, but less customizable
Authenticating Clients

ASP.NET
ASP.NET Membership provides a mechanism for storing
and validating users
Forms authentication user required to login with
username and password
Can be customized by creating a custom provider

You
Create a DelegatingHandler to authenticate the client
The implementation is up to you, maintainability is hard
You can create a different handler for each route
Creating a Custom Delegating Handler

public class AuthenticationMessageHandler : DelegatingHandler


{
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Headers.Authorization != null &&
request.Headers.Authorization.Scheme == "Basic")
{
var encodedUserPass = request.Headers.Authorization.Parameter.Trim();
var userPass = Encoding.Default.GetString(
Convert.FromBase64String(encodedUserPass));
var parts = userPass.Split(":".ToCharArray());
// Execute custom code to authenticate the user
bool isAuthenticated = AuthenticateIdentity(parts[0], parts[1]);
// Check authentication state - shown in the next slide
}
return base.SendAsync(request, cancellationToken);
}
}
Handling the Custom Authentication Result

if (isAuthenticated)
{
// User is valid. Create a principal for the user
IIdentity identity = new GenericIdentity(parts[0]);
IPrincipal principal = new GenericPrincipal(identity, new[] { "Users", "Admins" });
Thread.CurrentPrincipal = principal;
}
else
{
// Authentication failed
response = request.CreateResponse(System.Net.HttpStatusCode.Unauthorized);
response.Headers.Add("WWW-Authenticate", "Basic");
return response;
}
Authorizing Clients

The [Authorize] attribute verifies that the user has


been authenticated before invoking the action
The attribute can be applied to the entire web
application, a controller, or an action
Use the Users or Roles parameter to specify which
users/roles have access to specific controllers and
actions
The [AllowAnonymous] attribute can be used to
allow access to public actions inside a controller
Create custom authorization rules by deriving
from AuthorizationFilterAttribute
Authorizing Clients with Attributes

[Authorize]
public class ProductController : ApiController
{
[AllowAnonymous]
public HttpResponseMessage GetSpecific(int id) { ... }

public HttpResponseMessage Get() { ... }

[Authorize(Roles="Admins")]
public HttpResponseMessage Delete() { ... }
}
Demonstration: Creating Secured ASP.NET Web
API Services

In this demonstration, you will learn how to:


Create a delegating handler for authentication
Use the [Authorize] and [AllowAnonymous] attributes
Lesson 4: Injecting Dependencies into
Controllers

Dependency Injection
Using the ASP.NET Web API Dependency Resolver
Demonstration: Creating a Dependency Resolver
Dependency Injection

Dependency injection is a design pattern intended


to decouple software modules from their
dependencies
In order to achieve such decoupling,
dependencies are defined as interfaces and are
received as constructor or method parameters:
public class LocationsController : ApiController
{
public ILocationRepository Locations { get; set; }
public LocationsController(ILocationRepository locations)
{
Locations = locations;
}
}
Using the ASP.NET Web API Dependency
Resolver

ASP.NET Web API supports dependency injection


with the IDependencyResolver interface
Implement your custom resolver or use it to wrap
a known IoC Container, such as Unity, MEF, or
Ninject
Register the dependency resolver in the ASP.NET
Web API global configuration
Demonstration: Creating a Dependency Resolver

In this demonstration, you will learn how to create


a dependency resolver for ASP.NET Web API
Lab: Extending Travel Companions ASP.NET
Web API Services

Exercise 1: Creating a Dependency Resolver for


Repositories
Exercise 2: Adding OData Capabilities to the Flight
Schedule Service
Exercise 3: Applying Validation Rules in the
Booking Service
Exercise 4: Secure the communication between
client and server
Virtual Machine: 20487B-SEA-DEV-A
20487B-SEA-DEV-C
User name: Administrator
Password: Pa$$w0rd
Lab Scenario

Blue Yonder Airlines wishes to add more features


to their client application: searchable flight
schedule, getting an RSS feed for flight schedules,
and changing the way the client connects to the
service to use a secured HTTPS channel. In this
lab, you will implement the necessary changes to
the ASP.NET Web API services you previously
created. In addition, you will use these changes to
apply validations and dependency injection to the
services, to make them more secured,
manageable, and testable.
Lab Review

Why does using dependency injection make it


easier to change your code?

Вам также может понравиться