Middleware: The HTTP Pipeline in ASP.NET 5
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Allen, Scott
Middleware is the heart of the HTTP processing pipeline in ASP.NET 5. In this session we’ll see how middleware works and look at guidelines to interact with HTTP requests.
 I put together this presentation for developers who are coming into ASP.NET 5 who want to build MVC applications and everything that you can do with ASP.NET. I want you to be able to understand middleware and feel comfortable with it because even though this concept has been around in previous versions of ASP.NET and MVC, it's not nearly as important or today it is much more important to understand the middleware pieces than it was previously. So my first tip of this session is just to give you an idea of what middleware is about and so I will talk about corn for just a minute. When I was a kid growing up, my parents were big fans of preserving food for the winter time. So they would freeze corn and they would can things and all sorts of food that you would stock up in the pantry during the winter. And to process corn specifically, what we would do is start off with me. We would go out to a local farm, we would bring home 300 ears of corn and it was my job, I was the first one in line, to husk those ears and it was me, my mom and my dad. I would take the ears of corn that still had a husk on them, remove the husk, pass it to my mom, so to the next piece in this pipeline. She would take off the silk and use a knife to cut out bad kernels and anything that might be wrong with that ear, she would pass it to my dad who would throw like 12 ears into a pot of boiling water to blanch them and that kills the enzymes that sometimes make it take away the flavor when they sit in the freezer for a while. And then when they were finished blanching after a couple minutes, my dad would put them into an ice bath and then the process would reverse itself. We would come back up the pipeline. So once the ears of corn were cool, my dad would pass them back to my mom who would cut off the kernels with a knife, she would pass me all the cut-up kernels and it was my job to measure out those kernels and put them into bags. Until I was at the age where I was trusted with a knife, then sometimes me and my mom would swap jobs there. But this is essentially what Little Ware is about. It's about I want to process something and I want to process it in two directions. There's an incoming response, you can think of it, and there's an incoming request and there's an outgoing response. And those two parts of a transaction get to visit each piece of middleware. But it does also important to understand that me, since I'm at the front of this pipeline, this corn processing pipeline, if I saw an ear was obviously bad, I could throw it away. I didn't have to pass it to the next component in the pipeline. And just think of, instead of processing corn, processing in HTTP post request, and I have the ability to look at that request and inspect it and perhaps discard it or perhaps modify it, but if I like what I see, I can pass it on to the next component in this pipeline to my mom who ultimately will give it to my dad and then we have a response coming back that gets to be looked at by all these different pieces of middleware. So instead of mom and me and dad, think of logger, authorizer, router, the order here is important. If I want to log all of the requests coming in, I need to put the logger up front because if another piece of middleware like the authorizer drops one of these requests because someone's not authorized to post here, the logger would never see it, right? Simple concept. But you can also get the pieces of middleware that sort of branch out. So we might end up at some sort of router that looks at a request and says, well, now I have to figure out what controller this goes to. So a piece of middleware for ASP.net NBC might look at the request and say, oh, I see it's slash movies slash list. So I'm going to find the movies controller and find the list action and instantiate that controller and invoke that method. That's middleware. As told through a story about corn. Now the reason I think this is important is because a lot of people compare middleware to IHGTB modules. And I think that's a really bad comparison. And I think you have to completely erase those thoughts of, well, this is just like the HTTP processing pipeline in previous versions of ASP.net where we could register HTTP modules. It's completely different because in previous versions of ASP.net, the framework team wrote the HTTP pipeline that processed requests. And we really couldn't change that pipeline. We could register HTTP modules in here. But what they had to do was wait for events that the pipeline would raise. So there was a begin request event. There was a pre-request handler execute event, authenticate request. You couldn't rearrange those events. And you often got in a state where I went to authenticate the request. It would make sense to tap into the authenticate request event. But oh, acquire request state, that event comes later. So I don't have the session object that I might need to authenticate this request. And those were the kind of things that we always had to juggle in previous versions of ASP.net. Now we really have complete control of that pipeline. We can order things just the way we want. We can build something that only does what we need. And that gives us a lot of flexibility. It can also improve performance. You might have seen some of the performance benchmarks on github.com. Some of that is because of the pipeline. It can be very lean. Some of that is also because of something else that we're going to talk about here in just a second. So in order to understand just how important middleware is in the next version of ASP.net, let's talk about the hosting model just a bit. And what I'll do, actually, is go ahead and get started with a new solution. We'll call it NDC middleware. And I'll create an empty application. And let Visual Studio spin this up. And once that's finished, let's make it even emptier than empty because right now we actually have some middleware installed. Let me take these things out. And you've probably heard that if you drop files into www.root, that is the new public folder where files are served from in ASP.net. So let me just go ahead and create a new item which will just be a simple HTML page. And we'll call it index.html because that's a nice name for a default file. And just to see if we can serve this yet, we'll put in a hello. I try to run this application and if I go to the read of the website, I don't have any response. What if I go to index.html? There's still not going to be a response. At this point, our ASP.net application does absolutely nothing because we have no middleware installed. So you can't get anywhere until you install some middleware. But I do want to point out that one of the reasons this is now crucially important, one of the reasons I can't even serve static files anymore is because we're kind of circumventing IIS with this version of ASP.net. I just want to show you if I can find it where Visual Studio has launched, hopefully, IIS Express, but I don't see it, don't see it, don't see it. That is not the dnx.exe I am looking for. About ten lines. Oh, up here it is. Thank you. This is so small, even on my screen. All right. That dev environment.exe that is right there at the top, notice underneath of that a little bit, there is an IIS express.exe. So just like in the past, I run an ASP.net web application. It will spin up the development server for me. And then IIS express, notice that it is running dnx.exe. Oh, my. That's going to make people nauseous. This dnx.exe, and that is actually the host for my web application. Currently in ASP.net 5, IIS just becomes a proxy. It receives HTTP request and it forwardes the request directly into my ASP.net application. It doesn't try to serve up files from the file system. It doesn't do much of anything. Except, it does do process management. So for everyone that worries about, oh, my goodness, are we getting rid of IIS? No, IIS is still there as a proxy. It is still there to do things like, it can still recycle your application every X minutes or X days. It can still monitor the memory consumption of that application and recycle it if it exceeds a certain threshold and CPU percentages. All those things still apply. But a lot of the settings in IIS completely go away. For example, integrated pipeline versus other types of pipelines and what version of.net do I want to load? It doesn't matter what you set there anymore. Because IIS really is just spinning up dnx.exe to launch my web application. And that happens because inside of www.root, which is where you will point your virtual directory for ASP.net file applications, there is a web.config file in there. So web.config still hasn't completely gone away. And that web.config there is there only to configure IIS. And the web.config file looks like this. It's configuring system.webserver. Can you see that in the back? Thumbs up, thumbs down. I feel compelled to zoom in anyway. I don't know why. But the only thing this does is it registers a new HTTP handler, which is a component that sits in IIS. And what that handler is going to do is make IIS a reverse proxy. Take all the incoming requests and just forward them along too. And you can see the environment variables in here about launching a dnx process and passing along some arguments, which will basically tell it what hosts to listen on and things like that. And of course, all that can change when we move to.net CLI, but the HTTP platform handler will still be there. We're circumventing basically IIS. And that's why our middleware is so important, because we are now building the entire pipeline for our application. So IIS now is really about being a proxy, doing process management. And my application has complete control over the request and response processing. So I need a startup class. And I need this configure method, the one that takes an I application builder, because that's the interface I program against when I start adding middleware to process the different requests. There's also configure services where I can configure the IOC container. It's the constructor where a lot of people put what configuration files and load configuration constants that they're going to use. Those pieces are all there. But let's just, well, let me get to one more slide and see what it says. Yeah, configure. Use that I application builder interface to build your pipeline. You can also get access to a few other things like I hosting environment. If you want to find out more about the environment that you're in, for example, debug versus production, do you want to find out what physical file system path you were rooted at, you can find that sort of information out by injecting different interfaces, the logger. Let's go ahead. Basically, that's just asking for all the configured services. These are being injected by the container. So anything you register in the configure services method, you can inject in here. And there's two basic ways to add middleware to the application. Let me just flip over in the visual studio and we'll use a couple of those. App.run is not something you would put in a lot of applications, I suspect, because it's what we call terminal middleware. And actually, let me write it like this. Terminal middleware means this is a piece of middleware that's going to process the response and it's not going to pass it to the next thing in the queue. It's like having one person at the front of that corn processing pipeline that just looks at the corn, does something with it, and then returns it back. I'm going to use visual studio or resharper to generate a method so you can see what one looks like and then we can write it as a lambda expression. But app.run, you have to pass it a delegate that takes an HTTP context and returns a task. And inside of here, I could make this since it's task-related, I could make it an async method and I could await the result of doing context.response. So the context, by the way, not like the HTTP context of years past, it's a lot more lean, but it does give me access to the response object, let's me get to the headers, gives me access to a request object where I can write something asynchronously when I spell it correctly and let's write out hello. Write async is often an extension method, let's see what I did wrong here. Oh, yes. Thank you. Let's run this. All I'm going to do is hopefully save the file and refresh and that's one piece of middle wire in the pipeline. So even though I request index.html, it doesn't matter what the request is going to be, they all end up in that piece of code that just writes out hello, so a response even for the favorite icon would return that text. And then there's app.use. So app.use is a little bit different. Let me go ahead and rewrite this, though. You'll see a lot of people do in that situation is just write an async lambda, so the context goes to context.response.write async hello. And I'm going to put that at the bottom so that I can, and I want to await that, put that at the bottom so that before that happens, I can do an app.use. So app.use is a little bit different. I'm going to put my cursor in the right place and try that again. It is a function that takes a request delegate and returns a request delegate. This request delegate is the thing that is a method that returns task and takes an HTTP context. In other words, what this is saying is I'm going to take something that we'll call next. That basically represents the next piece of middleware in my processing pipeline. So it's a function that I can invoke. And when I invoke it, that's when I'm taking a piece of corn, passing it to the next thing that is in the pipeline. And what I'm going to return is something that takes an HTTP context and returns task. And let's do it this way. Let me do a console. Do I want to do a console? Yeah, a console. Debug. Debug.writeLine. Starting request. So if this is the first piece of middleware that is inside of here, that would be the first piece of code that executes when a request comes in. And then I could await what happens when I call the next component and pass along that context that I have. And then I could debug that write line something that we have ended the request. And once again, I could use some information about that request that I could print out here. And now what have I done? Oh, yeah, I need to make that an async lambda. This bit is async. Let's go ahead and actually do some string interpolation. And say we're starting a request for context.request.path and ending a request for context. I need to put the dollar sign in front. The jQuery selector. Context.request.path. There we go. All right. Try this. I guess I'll have to run it with debugging now to see any output, but that's okay. And while that's loading, let me go ahead and just file off another request here for index.html so we can see that. Come back into Visual Studio and open up the output window, which disappeared on me. And, uh-huh. No output. That's interesting. Well, why wouldn't it do that? Try it once more. That will give me time to wonder what is going on. That looks better. Okay. For whatever reason it appeared this time. Maybe I didn't. I don't know. I don't know. Starting a request for slash, ending a request for slash, starting another request for slash, ending a request for slash, and all of those requests should have returned the response hello, which they did. Making some sense? All right. Let's get into some more meteor topics. Remove this. All of this depends on that request delegate. This is the definition, again, for request delegate. It's a delegate, so you can use this type to declare variables that point to a method, methods that take an HTTP context and return a task. And we just used app.run, that's a terminal piece of middleware, because there is no ability to call to the next piece of middleware when you write an app.run. It doesn't get a next pointer. And there's app.use, where you have to return a request delegate, but you also take a request delegate, which will represent the next piece of middleware. And there's one more I want to show you, after this slide, apparently. Now typically, let me go back to the code for a second. If you are going to author middleware, as a day-to-day business developer, you're probably not going to author a lot of middleware, but you do need to still have the middleware configured properly and in the right order. We'll talk about that. If you do author middleware, I think middleware is going to fall in one of three categories. There's code that comes above the call to the next component. And that's typically code where you place the code when you care about the incoming request. So if you want to check authorization headers, if you want to look at cookies, if you want to determine the user's culture based on accept headers or something like that, you would write that code above the await. You would look at the incoming request and set something based on that information. If you're writing code after the await, well, when you call next, that request goes the rest of the way through the pipeline. It might reach a controller or a static file or something that is actually going to start producing a response. So if you write code after await, you're typically waiting for the response to be available. And then you want to do something like log things or check for exceptions or see how long that request took to process. And that's why I say there's typically three categories of middleware. Pieces of middleware that care about the incoming request, so all the codes above the next. And there's pieces of middleware that care about the response and all the codes after the next. And then there will be some middleware, like logging middleware, that wants to look at both the request and the response. There will be some overlap there. And one more piece of middleware, which I thought I had a slide for. But maybe that's later. A later slide, but that's okay. Let's use it now. I want to use app.map just to demonstrate that one. So with app.map, what you do is you pass a path string. So what I want to write is a piece of middleware, I'm sorry, what I'm going to write is something that's only going to happen when we are at slash error. And with app.map, you can basically fork the pipeline. With app.map, you can say, oh, we're going this direction now. We're going a different direction. And what you pass in is a sub instance of iApplicationBuilder, because now you're going to be configuring a pipeline just for this request. It will visit all the ones above that. But once you get to slash error, you won't go to, let's say, slash run. And what I could do inside of here is I could say, okay, when we reach here, let's just do a subapp.run where I take a context and I throw a new exception of some sort error. And once I have my syntax correct, which it is not, oh, that's not an expression, so I have to put in some code blocks here, I believe, to make that happy. And then hit control KD to do some formatting, let's try that out. I hit Romans out debugging again just to get the web server started again. I should be able to come to slash error and I get nothing. If I look at F12, you'll see I did get a status of 500 internal server error. I'll come back and show you how you can get a much nicer error display here in just a second. But that's app.map. Fork the pipeline and go to a different pipeline that will do all sorts of different processing. Well, there are some pieces, a little bit of, there is a little bit of magic inside of ESP.net that will look at what happened during the processing and do things like, oh, there was an exception, so let me change the status code. But it's very minimal processing like that. Yes, sir? Did it go through the first middle one now? It did. So one of the things that I'll make more clear a little bit later is that the order these are registered is the order in which things will happen. So this is the first piece of middleware, the request will always go through here. And if I ran with the debugger again, you would see that. You'll just have to trust me, though. What about, so this is simple, silly middleware. What if we wanted to write a more serious piece of middleware, let's say? I think I'll just include something inside of the same file so I don't have to switch between files so often. But if I'm going to write a serious piece of middleware, I might want to put it in a class definition so they can have fields and have it constructed and configured and so forth. So let me write a class called greeting middleware. And the whole key to this is that I'm going to register this type as something that should be installed as middleware. And when you do that, what ESP.NET will magically do, the cursor slipped away on me, is it will look for a method, one instance of this class called invoke, and it has to take an HTTP context and return a task. So it's very much like an app.run piece of middleware. But I can also do this to this class. I can give it a constructor that takes a request delegate, which will be the pointer to the next piece of middleware that's in the pipeline, whether that's a function or another object, I don't know, this piece of middleware doesn't care. But I will need to save that away if I ever want to call it from invoke. So inside of invoke, what I can do is I could say, let's see, if context.path, context, sorry,.request.path starts with the following URL segment slash greeting. This is one way to do it. Then I want to await a context.response.writeAsync, a greeting, exclamation point, because we're very excited. And yes, I'll have to make this async. Otherwise, we want to await a call to next passing in that context. So essentially, we only want to handle certain types of requests here, only requests that go to slash greeting. Otherwise, we're just going to pass it on to the next thing. If I want to install this piece of middleware in the pipeline, let's do it instead of, well, let's do it above app.run. There's a method useMiddleware. I say I want to use this type, greetingMiddleware. And I'm not going to pass in any additional parameters right now. I just want to see if this thing will work. So save all the files, and let's go to greeting, and I get a greeting, which is very good. But if I go to the root of the application, I get hello. So we went two different places in the pipeline, right? And just to prove to you that if I place this bit of middleware above my greeting middleware, my greeting middleware can never be called because app.run is terminal. It responds to a request to the root. It responds to a request to greeting. So let's move this back. Now if you're going to offer middleware, there's a common pattern that all of the middleware components offered by the ASP.net contributors follow. You can write a class, call it whatever you want. The common suffix, though, is middleware. And typically, you're going to write middleware that is going to be used in different applications, so there might be some configuration options involved. So let's write an options class that someone can use to configure, let's say, the path and the text that is displayed. So something like a public class greeting options. It'll be a class that has... Hello? Let's try that again. A class that has a path property, and that could be string or path string, and a property that is the text to display. And the idea is I want someone to be able to instantiate that and say options equals new greeting options. Options, options, options. Options are not...still not functioning this week. Options.path equals slash greeting. Options.text equals a configured greeting. Explanation point. And then I'm going to pass this into use middleware. Like so, and that will automatically come to me when the framework instantiates this class, it will just pass along as part of the constructor. So I can say, let me also take a greeting options called options. Use resharper to hide that off into a private field. And now down here starts with segments. I would want to use options....sorry, underscore options. Path, and display the text. Options.text. All right. See if this works. Control S and save. And we are at slash greeting, which is still the configured one, but now I get the configured greeting. So it took my options and it used those. And then there's one more thing that you commonly do with middleware. In addition to providing some configuration options, it would also be nice for the consumer of this middleware to not have to actually know the name of this type. It would be nice if instead of specifying that, I just said use greeting or use greeting page or whatever you want to call it. So to pull that off, all we need is an extension method on I application builder. So a public static class to host some extension method. So let's call it greeting extensions. It's not really going to matter what the name of the class is if I type of it. This is going to be a public static method that returns I application builder. It's nice to chain these things together called use greeting. It's an extension method for I application builder. And it's inside of here, oh, it would also take my options. So greeting options, options. And it's inside of here where I would say app.use middleware. And I know the name of my type that I want to use, greeting middleware. And pass along those options and return the app. Let's see if that all works. Sorry. Still working. But that's the common pattern that most middleware that you're running to follow. They'll have an extension method for you to use that's very friendly, like use authentication, use this, use that. They'll provide an options class that you can use to pass in to configure some behavior of that piece of middleware. And then you're off and running. That would be building some custom middleware. Forking middleware is a topic I already talked about where we use app.map to set up a sub application builder and go off in a different direction. And now we can finally start about talking about some of the built-in middleware and tips on using that middleware. So first of all, one of the things you'll see in nearly every new ASP.net application now because it's there in both the empty template and the full application template is this use IAS platform handler, which initially I found very confusing because I knew IIS platform handler, that's a component that sits in IAS. So am I loading the same component here inside of ASP.net? The answer is no. When you go to the source code, you realize what the goal of this particular piece of middleware is. It's basically required for Windows authentication. There's one thing that IAS will still do related to the HTTP request, and that is uncover the user's identity if there's a Windows identity token that is being passed along. So it'll find out my domain name and my user name. And the way that it will take that authentication ticket that's being passed to it and get it to me is what the platform handler will do inside of IAS if, by the way, if you have this forward Windows auth token equals true in web.config. If you have that there, when IAS forwards the request to my process, it will set an additional HTTP header, x-IS-Windows-Off token with a header-friendly representation of that token. And what use platform handler will do is just look at that token and then call some Win32 APIs to make sure it establishes the proper user identity for this particular request. So if you're not using Windows authentication, you don't have to have that piece of middleware use platform handler. It'll turn that token into a Windows principle and establish it as request.user. It's this Windows user. What about serving my index.html file in the www.root folder? That's the responsibility of middleware that is in the Microsoft.asp.statics files package. They can serve static. There's a couple of different pieces of middleware inside of here. There's a piece of middleware that will just serve static files. There's another piece of middleware that will allow user to browse directories. So if they go to a directory, they get to see a list of files inside. There's a different piece of middleware if you want to add default files. So for example, I cannot get to index.html as a default file unless that piece of middleware is there. I can demonstrate that. So inside of actually now we're going to go to project.json because I need to add another package which is the static files middleware. You might be saying, well, this is a lot of trouble just to serve static files that used to happen for me for free. Valid point. But again, you're building a very efficient pipeline, right? If you don't need that, you don't include it. So you can be very lean. We have that package. Now I should be able to go into startup.cs. And again, the placement of middleware is important. So maybe I would want to place this after the possible fork to the slash error. It just depends, I guess, if I want to serve something from a directory that starts with slash error. But let's app.use static files. And now I should finally be able to come back to the web browser and ask for index.html. And I get my index.html. That's good. What about if I go to the root of the website? That's running that other hello. So maybe we should differentiate between this two a little cleaner. Well, of course, that's in an h3, but we can say this is from index.html. So how would I get index.html served from a request to the root? That's when I could. Sorry. Let me put it here. App.use default files. Will it work there? No. Because ordering is important. That default file is middleware. It doesn't actually serve up anything. All it does is look at the incoming request, see that it's going to a directory, and then look inside of that directory for the default file names. Index.html is one of those. And if it sees one of those files, it will change the request object so that it's requesting index.html. That way later pieces of middleware, when they look at the request, they see, oh, we are requesting index.html. I can find that. Let me throw that in there. So I need to put that piece of middleware here. And that should finally work. So now we have our index.html. From a request to the root. And if you just want all those features, there is a use file server that you can use. And that includes directory browsing, default files, and static files. Now one other thing I've done with static files, let me flip over to another application here real quick. So here's an ASP.NET application where I wanted to serve files from www root. But I also wanted to serve files directly from a node modules directory that is in this project. And that's easy to do. You just need two pieces of middleware. One that will serve things from www root and one that will serve things from node modules. So this first call to app.usefileserver that will serve things from www root. I always say www because I usually get tongue tied trying to say www. And here's another file server. If I don't pass any options into usefileserver, it just uses the default serving folder, which is www. But this one, I'm setting things up to be a little bit differently. I'm going to ask for a new physical file provider that will point at the node modules directory. I'm going to say yes. Whenever there's a request to slash node underscore modules, then I want to serve up those files, pass in those options to that file server. And now I can have two folders at the top level that I'm serving files from. Now if there's a file, because the ordering is important, if there's a file called a.js and www root, that would get served before a file that's in node modules with the same name because that first piece of middleware would find it in the other folder. Make some sense? All right. Continuing on, what about errors? When I hit that error endpoint, that forked pipeline that I have, that's a different NuGet package that I have to get to, microsoft.aspnet.diagnostics. And it has a piece of middleware to show an exception page, it also has another piece of middleware that you can register an endpoint, you just want to hit and see some runtime information about the environment and what frameworks and what packages are loaded. Let's bring that in real quick. So over in project.json, let's go to diagnostics and bring in RC1. There we go. Save this. And let's register, let's say right after our logging, app.use developer exception page should be here. So the developer exception page shows a stack trace. So typically you'll have something like the code on the screen where you check what environment you're in. Are you in the development environment? And only register that piece of middleware when you're in, let's say, staging or development. You wouldn't necessarily do it for production. There's a different piece of middleware where you can register a friendly error page to go to and something bad happens. But if you can think about what this piece of middleware will do, think about what it looks like inside, it would basically look like this. It's going to, inside of its invoke method, it's going to try to execute that next piece of middleware, passing along a context, and basically catch any exceptions that come out. And then take those exceptions and try to build some HTML about what went wrong, the stack trace, the exception, and so forth. So if I go back to the app and hit the slash error endpoint now, I should get an exception page. Did I save everything? I saved everything. Did I refresh? Sorry? I couldn't hear you. I'm sorry. Did I just delete that line of code? Oh, yeah. Oh, my. Good thing the conference is almost over. I don't know if I could do one more session. There. That's the developer exception page. So stack trace, I can look at the query string, cookies, and headers, and all that good stuff. And there's also app.use runtime info page. I want that to respond to slash runtime. I think that's the default, but I should now be able to come to slash runtime. And it will tell me all sorts of information about what operating system, runtime version, runtime type, all the packages that are deleted, all that good stuff. So another piece of middleware. What about cores? Cores is also a piece of middleware. There's a couple different ways to use cores. If I app.use cores this way, or any time I app.use cores, I'm installing a piece of middleware that will reply with the appropriate cores headers to every request that comes in with an origin header. So if you're writing ASP.NMVC and you only want to use cross origin resource sharing on specific controllers, you probably wouldn't install the middleware. It's kind of like the nuclear option places cores headers everywhere. You probably just use an accept cores attribute that you can put on a controller. This one sort of, yeah, it goes everywhere. That's in the microsoft.asp.cores package. I'm going to skip a demo on that one just to make sure we get through all the material I want to get through. Do when you use session. No, there's no session by default unless I add both some services, which will configure some services into the IOC container like the I distributed or something that implements I distributed cache. And I have to also install middleware because it's the middleware that will look at an incoming request, look for the cookie that specifies the user's session ID, and then take that cookie to go to the caching source and retrieve the session information that I have stored in there. And the session information by default when you add caching will set up an in memory cache service, but it's very easy to add something like reds or SQL server and have a distributed cache. It just works. It's not more asp.net state server, but there's reds that you can use. What about authentication? I know Brock and Don talked a lot about asp.net authentication this week as well as Barry, so I won't spend a lot of time on this, but you install packages like microsoft.authentication.forms, microsoft.authentication.twitter, things like that. You'll be able to app.use some sort of authentication here. So that piece of middleware, app.use cookie authentication, when I need a user to be authenticated to reach some particular resource, first of all, it's that piece of middleware that can look at an incoming cookie and figure out if it's an authentication ticket and do whatever is required to turn that into a user property on my request object so I know who the user is. And if they're authenticated and what claims they have and so forth. I do want to show you one example of using this. Something I ran into in a somewhat real asp.net application that I was starting was the ability to protect static files. So in traditional asp.net, if I have a folder full of, let's say, PDFs that only certain users can download, I can drop a web.config file in that folder and set some authentication options and now, let's say, anonymous users are restricted to getting to that folder. There's no more web.config files that I can drop around and static files itself doesn't provide any features that say, you know, restrict anonymous users to getting to certain files so I took a look at what it would take to write something like that and I came up with a piece of middleware that looked a bit like this. It's called protect folder. Let me show you how it's used first. Inside of startup.cs, I can say, I want to protect the folder secret. I only want to allow users into this folder that this policy allows. So there's a lot of policy objects in the asp.net five where you can figure things like that particular policy is just going to make sure that we have an authenticated user. The built-in method that asp.net provides. But there's lots of options here where you could require a specific claim or require a specific role or require a specific user name. I just wanted to make sure they weren't anonymous users. So app.useprotect folder, that path, that policy name, what does the middleware look like? Just like the greeting middleware that we talked about, it takes, say, request delegate, it takes the options object, and now when a request is coming in, I'm going to see if the request.path starts with that path that I'm trying to protect. If so, I'm going to ask the authorization service. Where does that come from? Well, it turns out invoke is injectable. So anything that is inside of the container, the iSession, the iCache, the iHosting environment, anything that you want inside of invoke, you can just have the interface there and have it injected. I'm going to ask the authorization service to authorize this user against that policy, and that will make sure that that user, in this case, is authenticated. If they're not authorized, then I will ask the authentication service that's on the context object to challenge that user. So in forms-based authentication, that would result in a redirect to a login page, let's say. So relatively simple middleware, but there are some frustrating things that you just got for free in the previous environment that you might have to work a little bit harder to have it happen in this environment. When I was trying to figure out how to write that middleware, it wasn't obvious at first, and I can tell you one of the best sources of information, because there's not a lot of documentation out there on specific pieces of middleware or how to author middleware and how to author middleware that works with the authentication service, but there are, in the GitHub repositories for ASP.net, lots of unit tests. The unit tests are actually very beneficial. This snippet of code is from a unit test that is unit testing, if I remember, the cookie authentication middleware. I'll talk a little more about unit testing in just a bit, but they were basically setting up a situation where this is inside of a piece of middleware. They just wanted to set up a test environment where if the user comes to slash protected, make sure we get a 401 back. If they come to forbid, do this, sign out, do that, that gave me a lot of clues about how to, oh, this is how I get a user, this is how I drop their authentication cookie, this is how I challenge them and force them to log in, that sort of thing. This is the code example I just showed you. Again, not a lot of time I'm going to spend on the security stuff, but if you want to use ASP.net identity, that consists of services that you have to add, and that also consists of middleware, because again, it's that piece of middleware that's going to look at an incoming request and try to establish the user's identity for the later pieces of middleware that might have, you know, might challenge the user and say you have to be an admin or you have to be authenticated. NVC has a piece of middleware. Now you should probably have a, now you might have a pretty good idea of what use NVC would do. That piece of middleware will look at an incoming request, it will hand things off to the iRouter implementations and ASP.net NVC and basically ask the NVC router, is this a request you're going to handle? If NVC comes back and says no, I didn't use that, we can continue through the pipeline to something else and perhaps at the very end of our pipeline we could just have a friendly 404 page or something like that. But if NVC handles the request, it's not going to call into the next thing in the pipeline. It's going to produce a response and we go back up the pipeline. And yeah, if you do write middleware, it's actually amazingly easy to test middleware. You might think it's difficult. Any time we see HTTP contacts, we think that's going to be hard, right? But there is a package, microsoft.asp.testhost that you can reference from a unit testing project and it includes things like a test server. So here is an actual unit test from their repository where I'm building a middleware pipeline. So a web application builder class with a configure method, I want to test that the use cores middleware is responding with the appropriate headers. So I'm going to say if the origin is this and the method is this and there's this header here, then we can have a cores header applied. How would you test that? That test package has a test server that you just instantiate and then you can walk up to that server and create a request. It doesn't really have to go out over the network. You just create a request, add a header, send it and it will give you back a response object and you can see the asserts at the bottom. We're making sure we got the proper response, the proper headers. Fairly easy stuff, I think. It's a lot like in Web API 2, a lot of people would test stuff just by having an in-memory server that passed around HTTP request messages and HTTP response messages. This is very similar. So just some final tips. I pointed out several times order is important. I would have to put default files in front of static files to actually serve default files. If you are writing a piece of middleware that is going to await the next component in the pipeline, you typically have to assume that someone else in the pipeline, further down the pipeline, started responding to the request. They might have written out some headers and a large part of the body in a stream operation. If you write any code after awaiting the next component, you should probably check the has-started property of context.response. Because if it has started, you're going to have a difficult time doing something like writing headers again because the headers might have already been sent to the client. This piece of code that I have on the screen is actually the code from the use developer exception page middleware. It basically just immediately calls into the next thing and then sees if there's an exception. And down here would be a bunch of processing for printing out the stack trace and producing all that HTML. But if the context.response.has-started, if that's true, it basically gives up. Sorry. Can't do anything for you now. Another tip, just be aware that these middleware components are not instantiated per request. They're instantiated once at the beginning of the application. And so they will be handling multiple HTTP requests at the same time if you have enough concurrent users. So if you have some piece of static data or shared data, you have to be very careful about threading issues. If you want to communicate between pieces of middleware, there's a couple different ways to do it. The easy way to do it, perhaps not the best way, but there is still an htbcontext.items where it's basically a dictionary of string and string or maybe it's string and object. But you put things in, let's say, in one piece of middleware and go through the request, a later piece of middleware can pull that item out and inspect it. What you might consider, though, instead of doing that is registering a service that will hold state for two different pieces of middleware because you can register that service as a singleton or as scope to an HTTP transaction, all sorts of different options there, so it's a little more flexible, might be a little more testable. But you can always inject services into an invoke method of a piece of middleware. You're not forced to use context.items for those. One thing I was a little bit frustrated with was the extensibility model of existing middleware. So if there's an existing piece of middleware and I want to know when it's doing something specific, most middleware doesn't come with that option. Static files does come with an option where it raises sort of an event. It's really just an action that you can have. Oh, I'm about to prepare the response, so I can wire up a delegate to that and look at what it's about to do and see, oh, it's about to serve a file that is greater than 10,000 bytes, so I'll throw them an exception to stop that processing. But there's not many of those extensibility points in any of the built-in middleware. There's just a few of them, like just one in static files. It's about it. And if for some reason you need to create something inside of a piece of middleware, but you're not sure how long it has to be around, you just want to make sure that it gets cleaned up when the response is finished processing. There is a method register for dispose on the response object so that when the response is complete, ASP.NET will come in and clean things up for you. And that is all I have for you. Questions, concerns, comments, excitement. Yes, sir? Yes, sir? Oh, yeah, I think what you're saying, that's an interesting question. If a piece of middleware throws an exception, yeah, I wanted to run this with a debugger, sorry. First, I just wanted to show you what happens when I go to slash error right now, and I have the use developer exception page in there. And I can see that I have a starting request for slash error right here. We'll continue running. And look at the output again. I still get the end request. So if you have a piece of middleware that catches an exception and then doesn't let it propagate, other things up the pipeline will be able to execute. But if something is not handling an exception, it will blow through the stack and tunnel right through them. More questions. This side of the room is very far away. How much of this do you actually need to do to get a website running? You know, I think most teams will just use some out-of-the-box configurations. You'll be able to look at, let's say, the startup.cs when you do file a new application and do a full web application. You'll be able to look at that and say, yeah, I need all of this stuff. And you might rip out a piece or two here and there. But I think that's for most line of business applications would be somewhere along that line. But you still need to write very much the things that already existed before. Well you need to write your own middleware? Yeah. I mean, I see things like right now there are some things that we might need that just aren't provided as yet, like that ability to protect static files. That was a piece of middleware that I had to write. But I imagine there's a lot of organizations that want to do some specific logging of requests or looking at requests and sending things out to different servers, that sort of thing that could all be done just with middleware now. Well I'll hang around if there's more questions. Thank you for coming. Enjoy the conference. Thank you.
 I put together this presentation for developers who are coming into ASP.NET 5 who want to  build MVC applications and everything that you can do with ASP.NET.  I want you to be able to understand middleware and feel comfortable with it because even  though this concept has been around in previous versions of ASP.NET and MVC, it's not nearly  as important or today it is much more important to understand the middleware pieces than it  was previously.  So my first tip of this session is just to give you an idea of what middleware is about  and so I will talk about corn for just a minute.  When I was a kid growing up, my parents were big fans of preserving food for the winter  time.  So they would freeze corn and they would can things and all sorts of food that you would  stock up in the pantry during the winter.  And to process corn specifically, what we would do is start off with me.  We would go out to a local farm, we would bring home 300 ears of corn and it was my  job, I was the first one in line, to husk those ears and it was me, my mom and my dad.  I would take the ears of corn that still had a husk on them, remove the husk, pass it  to my mom, so to the next piece in this pipeline.  She would take off the silk and use a knife to cut out bad kernels and anything that might  be wrong with that ear, she would pass it to my dad who would throw like 12 ears into  a pot of boiling water to blanch them and that kills the enzymes that sometimes make  it take away the flavor when they sit in the freezer for a while.  And then when they were finished blanching after a couple minutes, my dad would put them  into an ice bath and then the process would reverse itself.  We would come back up the pipeline.  So once the ears of corn were cool, my dad would pass them back to my mom who would cut  off the kernels with a knife, she would pass me all the cut-up kernels and it was my job  to measure out those kernels and put them into bags.  Until I was at the age where I was trusted with a knife, then sometimes me and my mom  would swap jobs there.  But this is essentially what Little Ware is about.  It's about I want to process something and I want to process it in two directions.  There's an incoming response, you can think of it, and there's an incoming request and  there's an outgoing response.  And those two parts of a transaction get to visit each piece of middleware.  But it does also important to understand that me, since I'm at the front of this pipeline,  this corn processing pipeline, if I saw an ear was obviously bad, I could throw it away.  I didn't have to pass it to the next component in the pipeline.  And just think of, instead of processing corn, processing in HTTP post request, and I have  the ability to look at that request and inspect it and perhaps discard it or perhaps modify  it, but if I like what I see, I can pass it on to the next component in this pipeline  to my mom who ultimately will give it to my dad and then we have a response coming back  that gets to be looked at by all these different pieces of middleware.  So instead of mom and me and dad, think of logger, authorizer, router, the order here  is important.  If I want to log all of the requests coming in, I need to put the logger up front because  if another piece of middleware like the authorizer drops one of these requests because someone's  not authorized to post here, the logger would never see it, right?  Simple concept.  But you can also get the pieces of middleware that sort of branch out.  So we might end up at some sort of router that looks at a request and says, well, now  I have to figure out what controller this goes to.  So a piece of middleware for ASP.net NBC might look at the request and say, oh, I see it's  slash movies slash list.  So I'm going to find the movies controller and find the list action and instantiate that  controller and invoke that method.  That's middleware.  As told through a story about corn.  Now the reason I think this is important is because a lot of people compare middleware  to IHGTB modules.  And I think that's a really bad comparison.  And I think you have to completely erase those thoughts of, well, this is just like the HTTP  processing pipeline in previous versions of ASP.net where we could register HTTP modules.  It's completely different because in previous versions of ASP.net, the framework team wrote  the HTTP pipeline that processed requests.  And we really couldn't change that pipeline.  We could register HTTP modules in here.  But what they had to do was wait for events that the pipeline would raise.  So there was a begin request event.  There was a pre-request handler execute event, authenticate request.  You couldn't rearrange those events.  And you often got in a state where I went to authenticate the request.  It would make sense to tap into the authenticate request event.  But oh, acquire request state, that event comes later.  So I don't have the session object that I might need to authenticate this request.  And those were the kind of things that we always had to juggle in previous versions  of ASP.net.  Now we really have complete control of that pipeline.  We can order things just the way we want.  We can build something that only does what we need.  And that gives us a lot of flexibility.  It can also improve performance.  You might have seen some of the performance benchmarks on github.com.  Some of that is because of the pipeline.  It can be very lean.  Some of that is also because of something else that we're going to talk about here in  just a second.  So in order to understand just how important middleware is in the next version of ASP.net,  let's talk about the hosting model just a bit.  And what I'll do, actually, is go ahead and get started with a new solution.  We'll call it NDC middleware.  And I'll create an empty application.  And let Visual Studio spin this up.  And once that's finished, let's make it even emptier than empty because right now we actually  have some middleware installed.  Let me take these things out.  And you've probably heard that if you drop files into www.root, that is the new public  folder where files are served from in ASP.net.  So let me just go ahead and create a new item which will just be a simple HTML page.  And we'll call it index.html because that's a nice name for a default file.  And just to see if we can serve this yet, we'll put in a hello.  I try to run this application and if I go to the read of the website, I don't have any  response.  What if I go to index.html?  There's still not going to be a response.  At this point, our ASP.net application does absolutely nothing because we have no middleware  installed.  So you can't get anywhere until you install some middleware.  But I do want to point out that one of the reasons this is now crucially important, one  of the reasons I can't even serve static files anymore is because we're kind of circumventing  IIS with this version of ASP.net.  I just want to show you if I can find it where Visual Studio has launched, hopefully, IIS  Express, but I don't see it, don't see it, don't see it.  That is not the dnx.exe I am looking for.  About ten lines.  Oh, up here it is.  Thank you.  This is so small, even on my screen.  All right.  That dev environment.exe that is right there at the top, notice underneath of that a little  bit, there is an IIS express.exe.  So just like in the past, I run an ASP.net web application.  It will spin up the development server for me.  And then IIS express, notice that it is running dnx.exe.  Oh, my.  That's going to make people nauseous.  This dnx.exe, and that is actually the host for my web application.  Currently in ASP.net 5, IIS just becomes a proxy.  It receives HTTP request and it forwardes the request directly into my ASP.net application.  It doesn't try to serve up files from the file system.  It doesn't do much of anything.  Except, it does do process management.  So for everyone that worries about, oh, my goodness, are we getting rid of IIS?  No, IIS is still there as a proxy.  It is still there to do things like, it can still recycle your application every X minutes  or X days.  It can still monitor the memory consumption of that application and recycle it if it exceeds  a certain threshold and CPU percentages.  All those things still apply.  But a lot of the settings in IIS completely go away.  For example, integrated pipeline versus other types of pipelines and what version of.net  do I want to load?  It doesn't matter what you set there anymore.  Because IIS really is just spinning up dnx.exe to launch my web application.  And that happens because inside of www.root, which is where you will point your virtual  directory for ASP.net file applications, there is a web.config file in there.  So web.config still hasn't completely gone away.  And that web.config there is there only to configure IIS.  And the web.config file looks like this.  It's configuring system.webserver.  Can you see that in the back?  Thumbs up, thumbs down.  I feel compelled to zoom in anyway.  I don't know why.  But the only thing this does is it registers a new HTTP handler, which is a component that  sits in IIS.  And what that handler is going to do is make IIS a reverse proxy.  Take all the incoming requests and just forward them along too.  And you can see the environment variables in here about launching a dnx process and passing  along some arguments, which will basically tell it what hosts to listen on and things  like that.  And of course, all that can change when we move to.net CLI, but the HTTP platform handler  will still be there.  We're circumventing basically IIS.  And that's why our middleware is so important, because we are now building the entire pipeline  for our application.  So IIS now is really about being a proxy, doing process management.  And my application has complete control over the request and response processing.  So I need a startup class.  And I need this configure method, the one that takes an I application builder, because  that's the interface I program against when I start adding middleware to process the different  requests.  There's also configure services where I can configure the IOC container.  It's the constructor where a lot of people put what configuration files and load configuration  constants that they're going to use.  Those pieces are all there.  But let's just, well, let me get to one more slide and see what it says.  Yeah, configure.  Use that I application builder interface to build your pipeline.  You can also get access to a few other things like I hosting environment.  If you want to find out more about the environment that you're in, for example, debug versus  production, do you want to find out what physical file system path you were rooted at, you can  find that sort of information out by injecting different interfaces, the logger.  Let's go ahead.  Basically, that's just asking for all the configured services.  These are being injected by the container.  So anything you register in the configure services method, you can inject in here.  And there's two basic ways to add middleware to the application.  Let me just flip over in the visual studio and we'll use a couple of those.  App.run is not something you would put in a lot of applications, I suspect, because  it's what we call terminal middleware.  And actually, let me write it like this.  Terminal middleware means this is a piece of middleware that's going to process the response  and it's not going to pass it to the next thing in the queue.  It's like having one person at the front of that corn processing pipeline that just looks  at the corn, does something with it, and then returns it back.  I'm going to use visual studio or resharper to generate a method so you can see what one  looks like and then we can write it as a lambda expression.  But app.run, you have to pass it a delegate that takes an HTTP context and returns a  task.  And inside of here, I could make this since it's task-related, I could make it an async  method and I could await the result of doing context.response.  So the context, by the way, not like the HTTP context of years past, it's a lot more lean,  but it does give me access to the response object, let's me get to the headers, gives  me access to a request object where I can write something asynchronously when I spell  it correctly and let's write out hello.  Write async is often an extension method, let's see what I did wrong here.  Oh, yes.  Thank you.  Let's run this.  All I'm going to do is hopefully save the file and refresh and that's one piece of middle  wire in the pipeline.  So even though I request index.html, it doesn't matter what the request is going to be, they  all end up in that piece of code that just writes out hello, so a response even for the  favorite icon would return that text.  And then there's app.use.  So app.use is a little bit different.  Let me go ahead and rewrite this, though.  You'll see a lot of people do in that situation is just write an async lambda, so the context  goes to context.response.write async hello.  And I'm going to put that at the bottom so that I can, and I want to await that, put  that at the bottom so that before that happens, I can do an app.use.  So app.use is a little bit different.  I'm going to put my cursor in the right place and try that again.  It is a function that takes a request delegate and returns a request delegate.  This request delegate is the thing that is a method that returns task and takes an HTTP  context.  In other words, what this is saying is I'm going to take something that we'll call next.  That basically represents the next piece of middleware in my processing pipeline.  So it's a function that I can invoke.  And when I invoke it, that's when I'm taking a piece of corn, passing it to the next thing  that is in the pipeline.  And what I'm going to return is something that takes an HTTP context and returns task.  And let's do it this way.  Let me do a console.  Do I want to do a console?  Yeah, a console.  Debug.  Debug.writeLine.  Starting request.  So if this is the first piece of middleware that is inside of here, that would be the  first piece of code that executes when a request comes in.  And then I could await what happens when I call the next component and pass along that  context that I have.  And then I could debug that write line something that we have ended the request.  And once again, I could use some information about that request that I could print out here.  And now what have I done?  Oh, yeah, I need to make that an async lambda.  This bit is async.  Let's go ahead and actually do some string interpolation.  And say we're starting a request for context.request.path and ending a request for context.  I need to put the dollar sign in front.  The jQuery selector.  Context.request.path.  There we go.  All right.  Try this.  I guess I'll have to run it with debugging now to see any output, but that's okay.  And while that's loading, let me go ahead and just file off another request here for  index.html so we can see that.  Come back into Visual Studio and open up the output window, which disappeared on me.  And, uh-huh.  No output.  That's interesting.  Well, why wouldn't it do that?  Try it once more.  That will give me time to wonder what is going on.  That looks better.  Okay.  For whatever reason it appeared this time.  Maybe I didn't.  I don't know.  I don't know.  Starting a request for slash, ending a request for slash, starting another request for slash,  ending a request for slash, and all of those requests should have returned the response  hello, which they did.  Making some sense?  All right.  Let's get into some more meteor topics.  Remove this.  All of this depends on that request delegate.  This is the definition, again, for request delegate.  It's a delegate, so you can use this type to declare variables that point to a method,  methods that take an HTTP context and return a task.  And we just used app.run, that's a terminal piece of middleware, because there is no ability  to call to the next piece of middleware when you write an app.run.  It doesn't get a next pointer.  And there's app.use, where you have to return a request delegate, but you also take a request  delegate, which will represent the next piece of middleware.  And there's one more I want to show you, after this slide, apparently.  Now typically, let me go back to the code for a second.  If you are going to author middleware, as a day-to-day business developer, you're probably  not going to author a lot of middleware, but you do need to still have the middleware configured  properly and in the right order.  We'll talk about that.  If you do author middleware, I think middleware is going to fall in one of three categories.  There's code that comes above the call to the next component.  And that's typically code where you place the code when you care about the incoming  request.  So if you want to check authorization headers, if you want to look at cookies, if you want  to determine the user's culture based on accept headers or something like that, you  would write that code above the await.  You would look at the incoming request and set something based on that information.  If you're writing code after the await, well, when you call next, that request goes the  rest of the way through the pipeline.  It might reach a controller or a static file or something that is actually going to start  producing a response.  So if you write code after await, you're typically waiting for the response to be available.  And then you want to do something like log things or check for exceptions or see how  long that request took to process.  And that's why I say there's typically three categories of middleware.  Pieces of middleware that care about the incoming request, so all the codes above the next.  And there's pieces of middleware that care about the response and all the codes after  the next.  And then there will be some middleware, like logging middleware, that wants to look at  both the request and the response.  There will be some overlap there.  And one more piece of middleware, which I thought I had a slide for.  But maybe that's later.  A later slide, but that's okay.  Let's use it now.  I want to use app.map just to demonstrate that one.  So with app.map, what you do is you pass a path string.  So what I want to write is a piece of middleware, I'm sorry, what I'm going to write is something  that's only going to happen when we are at slash error.  And with app.map, you can basically fork the pipeline.  With app.map, you can say, oh, we're going this direction now.  We're going a different direction.  And what you pass in is a sub instance of iApplicationBuilder, because now you're going to be configuring  a pipeline just for this request.  It will visit all the ones above that.  But once you get to slash error, you won't go to, let's say, slash run.  And what I could do inside of here is I could say, okay, when we reach here, let's just do  a subapp.run where I take a context and I throw a new exception of some sort error.  And once I have my syntax correct, which it is not, oh, that's not an expression, so I  have to put in some code blocks here, I believe, to make that happy.  And then hit control KD to do some formatting, let's try that out.  I hit Romans out debugging again just to get the web server started again.  I should be able to come to slash error and I get nothing.  If I look at F12, you'll see I did get a status of 500 internal server error.  I'll come back and show you how you can get a much nicer error display here in just a  second.  But that's app.map.  Fork the pipeline and go to a different pipeline that will do all sorts of different processing.  Well, there are some pieces, a little bit of, there is a little bit of magic inside of  ESP.net that will look at what happened during the processing and do things like, oh, there  was an exception, so let me change the status code.  But it's very minimal processing like that.  Yes, sir?  Did it go through the first middle one now?  It did.  So one of the things that I'll make more clear a little bit later is that the order these  are registered is the order in which things will happen.  So this is the first piece of middleware, the request will always go through here.  And if I ran with the debugger again, you would see that.  You'll just have to trust me, though.  What about, so this is simple, silly middleware.  What if we wanted to write a more serious piece of middleware, let's say?  I think I'll just include something inside of the same file so I don't have to switch  between files so often.  But if I'm going to write a serious piece of middleware, I might want to put it in a class  definition so they can have fields and have it constructed and configured and so forth.  So let me write a class called greeting middleware.  And the whole key to this is that I'm going to register this type as something that should  be installed as middleware.  And when you do that, what ESP.NET will magically do, the cursor slipped away on me, is it will  look for a method, one instance of this class called invoke, and it has to take an HTTP  context and return a task.  So it's very much like an app.run piece of middleware.  But I can also do this to this class.  I can give it a constructor that takes a request delegate, which will be the pointer to the  next piece of middleware that's in the pipeline, whether that's a function or another object,  I don't know, this piece of middleware doesn't care.  But I will need to save that away if I ever want to call it from invoke.  So inside of invoke, what I can do is I could say, let's see, if context.path, context,  sorry,.request.path starts with the following URL segment slash greeting.  This is one way to do it.  Then I want to await a context.response.writeAsync, a greeting, exclamation point, because we're  very excited.  And yes, I'll have to make this async.  Otherwise, we want to await a call to next passing in that context.  So essentially, we only want to handle certain types of requests here, only requests that  go to slash greeting.  Otherwise, we're just going to pass it on to the next thing.  If I want to install this piece of middleware in the pipeline, let's do it instead of, well,  let's do it above app.run.  There's a method useMiddleware.  I say I want to use this type, greetingMiddleware.  And I'm not going to pass in any additional parameters right now.  I just want to see if this thing will work.  So save all the files, and let's go to greeting, and I get a greeting, which is very good.  But if I go to the root of the application, I get hello.  So we went two different places in the pipeline, right?  And just to prove to you that if I place this bit of middleware above my greeting middleware,  my greeting middleware can never be called because app.run is terminal.  It responds to a request to the root.  It responds to a request to greeting.  So let's move this back.  Now if you're going to offer middleware, there's a common pattern that all of the middleware  components offered by the ASP.net contributors follow.  You can write a class, call it whatever you want.  The common suffix, though, is middleware.  And typically, you're going to write middleware that is going to be used in different applications,  so there might be some configuration options involved.  So let's write an options class that someone can use to configure, let's say, the path  and the text that is displayed.  So something like a public class greeting options.  It'll be a class that has...  Hello?  Let's try that again.  A class that has a path property, and that could be string or path string, and a property  that is the text to display.  And the idea is I want someone to be able to instantiate that and say options equals  new greeting options.  Options, options, options.  Options are not...still not functioning this week.  Options.path equals slash greeting.  Options.text equals a configured greeting.  Explanation point.  And then I'm going to pass this into use middleware.  Like so, and that will automatically come to me when the framework instantiates this  class, it will just pass along as part of the constructor.  So I can say, let me also take a greeting options called options.  Use resharper to hide that off into a private field.  And now down here starts with segments.  I would want to use options....sorry, underscore options.  Path, and display the text.  Options.text.  All right.  See if this works.  Control S and save.  And we are at slash greeting, which is still the configured one, but now I get the configured  greeting.  So it took my options and it used those.  And then there's one more thing that you commonly do with middleware.  In addition to providing some configuration options, it would also be nice for the consumer  of this middleware to not have to actually know the name of this type.  It would be nice if instead of specifying that, I just said use greeting or use greeting  page or whatever you want to call it.  So to pull that off, all we need is an extension method on I application builder.  So a public static class to host some extension method.  So let's call it greeting extensions.  It's not really going to matter what the name of the class is if I type of it.  This is going to be a public static method that returns I application builder.  It's nice to chain these things together called use greeting.  It's an extension method for I application builder.  And it's inside of here, oh, it would also take my options.  So greeting options, options.  And it's inside of here where I would say app.use middleware.  And I know the name of my type that I want to use, greeting middleware.  And pass along those options and return the app.  Let's see if that all works.  Sorry.  Still working.  But that's the common pattern that most middleware that you're running to follow.  They'll have an extension method for you to use that's very friendly, like use authentication,  use this, use that.  They'll provide an options class that you can use to pass in to configure some behavior  of that piece of middleware.  And then you're off and running.  That would be building some custom middleware.  Forking middleware is a topic I already talked about where we use app.map to set up a sub  application builder and go off in a different direction.  And now we can finally start about talking about some of the built-in middleware and  tips on using that middleware.  So first of all, one of the things you'll see in nearly every new ASP.net application  now because it's there in both the empty template and the full application template is this  use IAS platform handler, which initially I found very confusing because I knew IIS platform  handler, that's a component that sits in IAS.  So am I loading the same component here inside of ASP.net?  The answer is no.  When you go to the source code, you realize what the goal of this particular piece of  middleware is.  It's basically required for Windows authentication.  There's one thing that IAS will still do related to the HTTP request, and that is uncover  the user's identity if there's a Windows identity token that is being passed along.  So it'll find out my domain name and my user name.  And the way that it will take that authentication ticket that's being passed to it and get it  to me is what the platform handler will do inside of IAS if, by the way, if you have  this forward Windows auth token equals true in web.config.  If you have that there, when IAS forwards the request to my process, it will set an  additional HTTP header, x-IS-Windows-Off token with a header-friendly representation  of that token.  And what use platform handler will do is just look at that token and then call some Win32  APIs to make sure it establishes the proper user identity for this particular request.  So if you're not using Windows authentication, you don't have to have that piece of middleware  use platform handler.  It'll turn that token into a Windows principle and establish it as request.user.  It's this Windows user.  What about serving my index.html file in the www.root folder?  That's the responsibility of middleware that is in the Microsoft.asp.statics files package.  They can serve static.  There's a couple of different pieces of middleware inside of here.  There's a piece of middleware that will just serve static files.  There's another piece of middleware that will allow user to browse directories.  So if they go to a directory, they get to see a list of files inside.  There's a different piece of middleware if you want to add default files.  So for example, I cannot get to index.html as a default file unless that piece of middleware  is there.  I can demonstrate that.  So inside of actually now we're going to go to project.json because I need to add another  package which is the static files middleware.  You might be saying, well, this is a lot of trouble just to serve static files that used  to happen for me for free.  Valid point.  But again, you're building a very efficient pipeline, right?  If you don't need that, you don't include it.  So you can be very lean.  We have that package.  Now I should be able to go into startup.cs.  And again, the placement of middleware is important.  So maybe I would want to place this after the possible fork to the slash error.  It just depends, I guess, if I want to serve something from a directory that starts with  slash error.  But let's app.use static files.  And now I should finally be able to come back to the web browser and ask for index.html.  And I get my index.html.  That's good.  What about if I go to the root of the website?  That's running that other hello.  So maybe we should differentiate between this two a little cleaner.  Well, of course, that's in an h3, but we can say this is from index.html.  So how would I get index.html served from a request to the root?  That's when I could.  Sorry.  Let me put it here.  App.use default files.  Will it work there?  No.  Because ordering is important.  That default file is middleware.  It doesn't actually serve up anything.  All it does is look at the incoming request, see that it's going to a directory, and then  look inside of that directory for the default file names.  Index.html is one of those.  And if it sees one of those files, it will change the request object so that it's requesting  index.html.  That way later pieces of middleware, when they look at the request, they see, oh, we  are requesting index.html.  I can find that.  Let me throw that in there.  So I need to put that piece of middleware here.  And that should finally work.  So now we have our index.html.  From a request to the root.  And if you just want all those features, there is a use file server that you can use.  And that includes directory browsing, default files, and static files.  Now one other thing I've done with static files, let me flip over to another application  here real quick.  So here's an ASP.NET application where I wanted to serve files from www root.  But I also wanted to serve files directly from a node modules directory that is in this  project.  And that's easy to do.  You just need two pieces of middleware.  One that will serve things from www root and one that will serve things from node modules.  So this first call to app.usefileserver that will serve things from www root.  I always say www because I usually get tongue tied trying to say www.  And here's another file server.  If I don't pass any options into usefileserver, it just uses the default serving folder, which  is www.  But this one, I'm setting things up to be a little bit differently.  I'm going to ask for a new physical file provider that will point at the node modules  directory.  I'm going to say yes.  Whenever there's a request to slash node underscore modules, then I want to serve up those files,  pass in those options to that file server.  And now I can have two folders at the top level that I'm serving files from.  Now if there's a file, because the ordering is important, if there's a file called a.js  and www root, that would get served before a file that's in node modules with the same  name because that first piece of middleware would find it in the other folder.  Make some sense?  All right.  Continuing on, what about errors?  When I hit that error endpoint, that forked pipeline that I have, that's a different  NuGet package that I have to get to, microsoft.aspnet.diagnostics.  And it has a piece of middleware to show an exception page, it also has another piece  of middleware that you can register an endpoint, you just want to hit and see some runtime  information about the environment and what frameworks and what packages are loaded.  Let's bring that in real quick.  So over in project.json, let's go to diagnostics and bring in RC1.  There we go.  Save this.  And let's register, let's say right after our logging, app.use developer exception page  should be here.  So the developer exception page shows a stack trace.  So typically you'll have something like the code on the screen where you check what environment  you're in.  Are you in the development environment?  And only register that piece of middleware when you're in, let's say, staging or development.  You wouldn't necessarily do it for production.  There's a different piece of middleware where you can register a friendly error page to go  to and something bad happens.  But if you can think about what this piece of middleware will do, think about what it  looks like inside, it would basically look like this.  It's going to, inside of its invoke method, it's going to try to execute that next piece  of middleware, passing along a context, and basically catch any exceptions that come out.  And then take those exceptions and try to build some HTML about what went wrong, the  stack trace, the exception, and so forth.  So if I go back to the app and hit the slash error endpoint now, I should get an exception  page.  Did I save everything?  I saved everything.  Did I refresh?  Sorry?  I couldn't hear you.  I'm sorry.  Did I just delete that line of code?  Oh, yeah.  Oh, my.  Good thing the conference is almost over.  I don't know if I could do one more session.  There.  That's the developer exception page.  So stack trace, I can look at the query string, cookies, and headers, and all that good stuff.  And there's also app.use runtime info page.  I want that to respond to slash runtime.  I think that's the default, but I should now be able to come to slash runtime.  And it will tell me all sorts of information about what operating system, runtime version,  runtime type, all the packages that are deleted, all that good stuff.  So another piece of middleware.  What about cores?  Cores is also a piece of middleware.  There's a couple different ways to use cores.  If I app.use cores this way, or any time I app.use cores, I'm installing a piece of middleware  that will reply with the appropriate cores headers to every request that comes in with  an origin header.  So if you're writing ASP.NMVC and you only want to use cross origin resource sharing  on specific controllers, you probably wouldn't install the middleware.  It's kind of like the nuclear option places cores headers everywhere.  You probably just use an accept cores attribute that you can put on a controller.  This one sort of, yeah, it goes everywhere.  That's in the microsoft.asp.cores package.  I'm going to skip a demo on that one just to make sure we get through all the material  I want to get through.  Do when you use session.  No, there's no session by default unless I add both some services, which will configure  some services into the IOC container like the I distributed or something that implements  I distributed cache.  And I have to also install middleware because it's the middleware that will look at an incoming  request, look for the cookie that specifies the user's session ID, and then take that  cookie to go to the caching source and retrieve the session information that I have stored  in there.  And the session information by default when you add caching will set up an in memory cache  service, but it's very easy to add something like reds or SQL server and have a distributed  cache.  It just works.  It's not more asp.net state server, but there's reds that you can use.  What about authentication?  I know Brock and Don talked a lot about asp.net authentication this week as well as Barry,  so I won't spend a lot of time on this, but you install packages like microsoft.authentication.forms,  microsoft.authentication.twitter, things like that.  You'll be able to app.use some sort of authentication here.  So that piece of middleware, app.use cookie authentication, when I need a user to be authenticated  to reach some particular resource, first of all, it's that piece of middleware that can  look at an incoming cookie and figure out if it's an authentication ticket and do whatever  is required to turn that into a user property on my request object so I know who the user  is.  And if they're authenticated and what claims they have and so forth.  I do want to show you one example of using this.  Something I ran into in a somewhat real asp.net application that I was starting was the ability  to protect static files.  So in traditional asp.net, if I have a folder full of, let's say, PDFs that only certain  users can download, I can drop a web.config file in that folder and set some authentication  options and now, let's say, anonymous users are restricted to getting to that folder.  There's no more web.config files that I can drop around and static files itself doesn't  provide any features that say, you know, restrict anonymous users to getting to certain files  so I took a look at what it would take to write something like that and I came up with  a piece of middleware that looked a bit like this.  It's called protect folder.  Let me show you how it's used first.  Inside of startup.cs, I can say, I want to protect the folder secret.  I only want to allow users into this folder that this policy allows.  So there's a lot of policy objects in the asp.net five where you can figure things like that  particular policy is just going to make sure that we have an authenticated user.  The built-in method that asp.net provides.  But there's lots of options here where you could require a specific claim or require  a specific role or require a specific user name.  I just wanted to make sure they weren't anonymous users.  So app.useprotect folder, that path, that policy name, what does the middleware look  like?  Just like the greeting middleware that we talked about, it takes, say, request delegate, it  takes the options object, and now when a request is coming in, I'm going to see if the request.path  starts with that path that I'm trying to protect.  If so, I'm going to ask the authorization service.  Where does that come from?  Well, it turns out invoke is injectable.  So anything that is inside of the container, the iSession, the iCache, the iHosting environment,  anything that you want inside of invoke, you can just have the interface there and have  it injected.  I'm going to ask the authorization service to authorize this user against that policy,  and that will make sure that that user, in this case, is authenticated.  If they're not authorized, then I will ask the authentication service that's on the context  object to challenge that user.  So in forms-based authentication, that would result in a redirect to a login page, let's  say.  So relatively simple middleware, but there are some frustrating things that you just  got for free in the previous environment that you might have to work a little bit harder  to have it happen in this environment.  When I was trying to figure out how to write that middleware, it wasn't obvious at first,  and I can tell you one of the best sources of information, because there's not a lot  of documentation out there on specific pieces of middleware or how to author middleware  and how to author middleware that works with the authentication service, but there are,  in the GitHub repositories for ASP.net, lots of unit tests.  The unit tests are actually very beneficial.  This snippet of code is from a unit test that is unit testing, if I remember, the cookie  authentication middleware.  I'll talk a little more about unit testing in just a bit, but they were basically setting  up a situation where this is inside of a piece of middleware.  They just wanted to set up a test environment where if the user comes to slash protected,  make sure we get a 401 back.  If they come to forbid, do this, sign out, do that, that gave me a lot of clues about  how to, oh, this is how I get a user, this is how I drop their authentication cookie,  this is how I challenge them and force them to log in, that sort of thing.  This is the code example I just showed you.  Again, not a lot of time I'm going to spend on the security stuff, but if you want to  use ASP.net identity, that consists of services that you have to add, and that also consists  of middleware, because again, it's that piece of middleware that's going to look at an incoming  request and try to establish the user's identity for the later pieces of middleware that might  have, you know, might challenge the user and say you have to be an admin or you have to  be authenticated.  NVC has a piece of middleware.  Now you should probably have a, now you might have a pretty good idea of what use NVC would  do.  That piece of middleware will look at an incoming request, it will hand things off to the iRouter  implementations and ASP.net NVC and basically ask the NVC router, is this a request you're  going to handle?  If NVC comes back and says no, I didn't use that, we can continue through the pipeline  to something else and perhaps at the very end of our pipeline we could just have a friendly  404 page or something like that.  But if NVC handles the request, it's not going to call into the next thing in the pipeline.  It's going to produce a response and we go back up the pipeline.  And yeah, if you do write middleware, it's actually amazingly easy to test middleware.  You might think it's difficult.  Any time we see HTTP contacts, we think that's going to be hard, right?  But there is a package, microsoft.asp.testhost that you can reference from a unit testing  project and it includes things like a test server.  So here is an actual unit test from their repository where I'm building a middleware  pipeline.  So a web application builder class with a configure method, I want to test that the  use cores middleware is responding with the appropriate headers.  So I'm going to say if the origin is this and the method is this and there's this header  here, then we can have a cores header applied.  How would you test that?  That test package has a test server that you just instantiate and then you can walk up  to that server and create a request.  It doesn't really have to go out over the network.  You just create a request, add a header, send it and it will give you back a response object  and you can see the asserts at the bottom.  We're making sure we got the proper response, the proper headers.  Fairly easy stuff, I think.  It's a lot like in Web API 2, a lot of people would test stuff just by having an in-memory  server that passed around HTTP request messages and HTTP response messages.  This is very similar.  So just some final tips.  I pointed out several times order is important.  I would have to put default files in front of static files to actually serve default  files.  If you are writing a piece of middleware that is going to await the next component in the  pipeline, you typically have to assume that someone else in the pipeline, further down  the pipeline, started responding to the request.  They might have written out some headers and a large part of the body in a stream operation.  If you write any code after awaiting the next component, you should probably check the has-started  property of context.response.  Because if it has started, you're going to have a difficult time doing something like  writing headers again because the headers might have already been sent to the client.  This piece of code that I have on the screen is actually the code from the use developer  exception page middleware.  It basically just immediately calls into the next thing and then sees if there's an exception.  And down here would be a bunch of processing for printing out the stack trace and producing  all that HTML.  But if the context.response.has-started, if that's true, it basically gives up.  Sorry.  Can't do anything for you now.  Another tip, just be aware that these middleware components are not instantiated per request.  They're instantiated once at the beginning of the application.  And so they will be handling multiple HTTP requests at the same time if you have enough  concurrent users.  So if you have some piece of static data or shared data, you have to be very careful about  threading issues.  If you want to communicate between pieces of middleware, there's a couple different  ways to do it.  The easy way to do it, perhaps not the best way, but there is still an htbcontext.items  where it's basically a dictionary of string and string or maybe it's string and object.  But you put things in, let's say, in one piece of middleware and go through the request,  a later piece of middleware can pull that item out and inspect it.  What you might consider, though, instead of doing that is registering a service that will  hold state for two different pieces of middleware because you can register that service as a  singleton or as scope to an HTTP transaction, all sorts of different options there, so it's  a little more flexible, might be a little more testable.  But you can always inject services into an invoke method of a piece of middleware.  You're not forced to use context.items for those.  One thing I was a little bit frustrated with was the extensibility model of existing middleware.  So if there's an existing piece of middleware and I want to know when it's doing something  specific, most middleware doesn't come with that option.  Static files does come with an option where it raises sort of an event.  It's really just an action that you can have.  Oh, I'm about to prepare the response, so I can wire up a delegate to that and look at  what it's about to do and see, oh, it's about to serve a file that is greater than 10,000  bytes, so I'll throw them an exception to stop that processing.  But there's not many of those extensibility points in any of the built-in middleware.  There's just a few of them, like just one in static files.  It's about it.  And if for some reason you need to create something inside of a piece of middleware,  but you're not sure how long it has to be around, you just want to make sure that it  gets cleaned up when the response is finished processing.  There is a method register for dispose on the response object so that when the response  is complete, ASP.NET will come in and clean things up for you.  And that is all I have for you.  Questions, concerns, comments, excitement.  Yes, sir?  Yes, sir?  Oh, yeah, I think what you're saying, that's an interesting question.  If a piece of middleware throws an exception, yeah, I wanted to run this with a debugger,  sorry.  First, I just wanted to show you what happens when I go to slash error right now, and I  have the use developer exception page in there.  And I can see that I have a starting request for slash error right here.  We'll continue running.  And look at the output again.  I still get the end request.  So if you have a piece of middleware that catches an exception and then doesn't let it propagate,  other things up the pipeline will be able to execute.  But if something is not handling an exception, it will blow through the stack and tunnel right  through them.  More questions.  This side of the room is very far away.  How much of this do you actually need to do to get a website running?  You know, I think most teams will just use some out-of-the-box configurations.  You'll be able to look at, let's say, the startup.cs when you do file a new application  and do a full web application.  You'll be able to look at that and say, yeah, I need all of this stuff.  And you might rip out a piece or two here and there.  But I think that's for most line of business applications would be somewhere along that  line.  But you still need to write very much the things that already existed before.  Well you need to write your own middleware?  Yeah.  I mean, I see things like right now there are some things that we might need that just  aren't provided as yet, like that ability to protect static files.  That was a piece of middleware that I had to write.  But I imagine there's a lot of organizations that want to do some specific logging of requests  or looking at requests and sending things out to different servers, that sort of thing  that could all be done just with middleware now.  Well I'll hang around if there's more questions.  Thank you for coming.  Enjoy the conference.  Thank you.
Middleware_Tips_and_Tricks_for_ASP_0_9479.png Middleware_Tips_and_Tricks_for_ASP_9480_9623.png Middleware_Tips_and_Tricks_for_ASP_9624_10043.png Middleware_Tips_and_Tricks_for_ASP_10044_11303.png Middleware_Tips_and_Tricks_for_ASP_11304_11375.png Middleware_Tips_and_Tricks_for_ASP_11376_11999.png Middleware_Tips_and_Tricks_for_ASP_12000_12227.png Middleware_Tips_and_Tricks_for_ASP_12228_12599.png Middleware_Tips_and_Tricks_for_ASP_12600_13091.png Middleware_Tips_and_Tricks_for_ASP_13092_13187.png Middleware_Tips_and_Tricks_for_ASP_13188_15731.png Middleware_Tips_and_Tricks_for_ASP_15732_18599.png Middleware_Tips_and_Tricks_for_ASP_18600_18695.png Middleware_Tips_and_Tricks_for_ASP_18696_20411.png Middleware_Tips_and_Tricks_for_ASP_20412_22319.png Middleware_Tips_and_Tricks_for_ASP_22320_22619.png Middleware_Tips_and_Tricks_for_ASP_22620_23159.png Middleware_Tips_and_Tricks_for_ASP_23160_24107.png Middleware_Tips_and_Tricks_for_ASP_24108_24479.png Middleware_Tips_and_Tricks_for_ASP_24480_26459.png Middleware_Tips_and_Tricks_for_ASP_26460_27563.png Middleware_Tips_and_Tricks_for_ASP_27564_28631.png Middleware_Tips_and_Tricks_for_ASP_28632_28871.png Middleware_Tips_and_Tricks_for_ASP_28872_29087.png Middleware_Tips_and_Tricks_for_ASP_29088_32819.png Middleware_Tips_and_Tricks_for_ASP_32820_35891.png Middleware_Tips_and_Tricks_for_ASP_35892_35999.png Middleware_Tips_and_Tricks_for_ASP_36000_37187.png Middleware_Tips_and_Tricks_for_ASP_37188_41891.png Middleware_Tips_and_Tricks_for_ASP_41892_42119.png Middleware_Tips_and_Tricks_for_ASP_42120_42467.png Middleware_Tips_and_Tricks_for_ASP_42468_42587.png Middleware_Tips_and_Tricks_for_ASP_42588_42635.png Middleware_Tips_and_Tricks_for_ASP_42636_42743.png Middleware_Tips_and_Tricks_for_ASP_42744_42923.png Middleware_Tips_and_Tricks_for_ASP_42924_43235.png Middleware_Tips_and_Tricks_for_ASP_43236_43331.png Middleware_Tips_and_Tricks_for_ASP_43332_43475.png Middleware_Tips_and_Tricks_for_ASP_43476_43763.png Middleware_Tips_and_Tricks_for_ASP_43764_45203.png Middleware_Tips_and_Tricks_for_ASP_45204_47159.png Middleware_Tips_and_Tricks_for_ASP_47160_47519.png Middleware_Tips_and_Tricks_for_ASP_47520_47651.png Middleware_Tips_and_Tricks_for_ASP_47652_49751.png Middleware_Tips_and_Tricks_for_ASP_49752_55703.png Middleware_Tips_and_Tricks_for_ASP_55704_56375.png Middleware_Tips_and_Tricks_for_ASP_56376_56579.png Middleware_Tips_and_Tricks_for_ASP_56580_56711.png Middleware_Tips_and_Tricks_for_ASP_56712_57047.png Middleware_Tips_and_Tricks_for_ASP_57048_57119.png Middleware_Tips_and_Tricks_for_ASP_57120_57203.png Middleware_Tips_and_Tricks_for_ASP_57204_57527.png Middleware_Tips_and_Tricks_for_ASP_57528_57959.png Middleware_Tips_and_Tricks_for_ASP_57960_58235.png Middleware_Tips_and_Tricks_for_ASP_58236_58523.png Middleware_Tips_and_Tricks_for_ASP_58524_61307.png Middleware_Tips_and_Tricks_for_ASP_61308_63407.png Middleware_Tips_and_Tricks_for_ASP_63408_64295.png Middleware_Tips_and_Tricks_for_ASP_64296_64415.png Middleware_Tips_and_Tricks_for_ASP_64416_64499.png Middleware_Tips_and_Tricks_for_ASP_64500_64811.png Middleware_Tips_and_Tricks_for_ASP_64812_65135.png Middleware_Tips_and_Tricks_for_ASP_65136_65531.png Middleware_Tips_and_Tricks_for_ASP_65532_65903.png Middleware_Tips_and_Tricks_for_ASP_65904_65975.png Middleware_Tips_and_Tricks_for_ASP_65976_66167.png Middleware_Tips_and_Tricks_for_ASP_66168_66263.png Middleware_Tips_and_Tricks_for_ASP_66264_66359.png Middleware_Tips_and_Tricks_for_ASP_66360_70799.png Middleware_Tips_and_Tricks_for_ASP_70800_73343.png Middleware_Tips_and_Tricks_for_ASP_73344_74963.png Middleware_Tips_and_Tricks_for_ASP_74964_79403.png Middleware_Tips_and_Tricks_for_ASP_79404_79967.png Middleware_Tips_and_Tricks_for_ASP_79968_80087.png Middleware_Tips_and_Tricks_for_ASP_80088_80999.png Middleware_Tips_and_Tricks_for_ASP_81000_87635.png Middleware_Tips_and_Tricks_for_ASP_87636_88283.png Middleware_Tips_and_Tricks_for_ASP_88284_88367.png Middleware_Tips_and_Tricks_for_ASP_88368_88451.png Middleware_Tips_and_Tricks_for_ASP_88452_88715.png Middleware_Tips_and_Tricks_for_ASP_88716_91574.png