We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Middleware: The HTTP Pipeline in ASP.NET 5

00:00

Formal Metadata

Title
Middleware: The HTTP Pipeline in ASP.NET 5
Alternative Title
Middleware: Tips and Tricks for ASP.NET 5
Title of Series
Number of Parts
133
Author
License
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
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
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.
36
61
Thumbnail
1:11:04
73
107
WeightApplication service providerSoftware developerProcess (computing)FamilyData modelSoftware developerRevision controlPresentation of a groupQuicksortMultiplication signGroup actionKernel (computing)Branch (computer science)Module (mathematics)State of matterHand fanAuthorizationEvent horizonBuildingEndliche ModelltheorieMaizeAuthenticationMiddlewareMathematicsInheritance (object-oriented programming)Connectivity (graph theory)Water vaporSoftware frameworkSinc functionApplication service providerMessage passingProcess (computing)Cartesian coordinate systemMereologyBenchmarkDirection (geometry)Order (biology)Game controllerDatabase transactionDependent and independent variablesRouter (computing)Electronic mailing listObject (grammar)Drop (liquid)Video gameVotingComputer networkGoodness of fitSocial classBitLine (geometry)Pairwise comparisonLatent heat2 (number)Sign (mathematics)Different (Kate Ryan album)Computer animation
Data modelSoftware developerNormed vector spaceApplication service providerExtension (kinesiology)Cartesian coordinate systemSystem callInstallation artDependent and independent variablesWebsiteComputer fileFigurate numberObservational studyPoint (geometry)Default (computer science)RootApplication service providerComputer animationSource code
Software developerCodeDemonComa BerenicesVideo game consoleWindowBuildingCartesian coordinate systemApplication service providerDependent and independent variablesComputer fileRevision control2 (number)Visualization (computer graphics)Physical systemSet (mathematics)ExpressionIntegrated development environmentServer (computing)Proxy serverSemiconductor memoryData managementWeightThresholding (image processing)Web applicationTouchscreenProcess (computing)Software developerObservational studyGoodness of fitBitINTEGRALLine (geometry)Web 2.0BefehlsprozessorType theoryComputer animationSource code
Software developerData modelProcess (computing)Data managementDependent and independent variablesProxy serverArithmetic meanWeightInternet service providerConfiguration spaceSocial classHoaxFigurate numberDirectory serviceWeb 2.0RoutingThumbnailComputer fileCartesian coordinate systemVariable (mathematics)Configuration spaceConstructor (object-oriented programming)2 (number)Integrated development environmentLogical constantWeightInternet service providerMiddlewareProcess (computing)Computer programmingConnectivity (graph theory)Structural loadInterface (computing)Computing platformDependent and independent variablesSocial classKnowledge-based configurationData managementEntire functionParameter (computer programming)Proxy serverDirect numerical simulationServer (computing)Message passingGame controllerComputer animation
Software developerSocial classWeightParameter (computer programming)Internet service providerQuicksortInternet service providerIntegrated development environmentPhysical systemCartesian coordinate systemRadical (chemistry)Interface (computing)Product (business)PhysicalismOptical disc driveInformationConfiguration spaceFile systemVisualization (computer graphics)Computer animationJSON
Software developerMobile appTask (computing)Computer fileQueue (abstract data type)ResultantMaizeObject (grammar)MiddlewareContext awarenessProcess (computing)Extension (kinesiology)Lambda calculusDependent and independent variablesRadical (chemistry)Direction (geometry)Bit rateDirected graphTheory of relativityExpressionCategory of beingSource code
Software developerContext awarenessInternet service providerData centerDependent and independent variablesSubject indexingCodeComputer iconBitObservational studyMiddlewareMobile appDifferent (Kate Ryan album)Functional (mathematics)InformationComputer virusLambda calculusTask (computing)String (computer science)Context awarenessGreatest elementSystem callInterpolationLoginFunction (mathematics)Process (computing)Software bugLabour Party (Malta)PlanningCursor (computers)MaizeLine (geometry)WordVideo game consoleAreaBus (computing)Computer animationSource code
Software developerMoving averageObservational studySubject indexingMultiplication signOpen setWindowFunction (mathematics)Hidden Markov modelComputer animation
Software developerDependent and independent variablesContext awarenessDigitale VideotechnikExecution unitoutputParameter (computer programming)Mountain passDependent and independent variablesSlosh dynamicsObservational studyMultiplication signRight angleType theoryVariable (mathematics)MiddlewareRadical (chemistry)Context awareness2 (number)Mobile appAuthorizationCodeSlide rulePointer (computer programming)FamilySource codeComputer animationJSON
Software developerConfiguration spaceFluid staticsCategory of beingEmailDependent and independent variablesWater vaporCodeSoftware developerGame controllerBit rateConnectivity (graph theory)HTTP cookieCodeSystem callWeightInformationAuthorizationWritingRight angleComputer fileLoginSubsetMiddlewareSource code
Software developerCategory of beingDependent and independent variablesConstructor (object-oriented programming)Slide ruleCodeMiddlewareDependent and independent variablesCategory of beingBitMobile appBlock (periodic table)Web 2.0Direction (geometry)Game controllerServer (computing)CodeError messageException handlingContext awarenessLevel (video gaming)Instance (computer science)Game theoryLipschitz-StetigkeitFile formatStreaming media1 (number)Internet service providerExpressionSource code
Software developerError message2 (number)Electronic visual displayQuicksortProcess (computing)Different (Kate Ryan album)Application service providerBitCodeMobile appException handlingComputer animationSource code
Software developerConstructor (object-oriented programming)Order (biology)BitInstance (computer science)Pointer (computer programming)Functional (mathematics)DebuggerType theoryMobile appSocial classMiddlewareContext awarenessComputer fileConstructor (object-oriented programming)Parameter (computer programming)System callMessage passingKey (cryptography)Uniform resource locatorField (computer science)WeightVotingReading (process)Object (grammar)Task (computing)Dependent and independent variablesPoint (geometry)Bit rateSource code
Software developerDependent and independent variablesRootRoutingRight angleOperator (mathematics)Radical (chemistry)Reading (process)MiddlewareBitConnectivity (graph theory)Application service providerSystem callElectronic visual displayComputer configurationString (computer science)Category of beingConstructor (object-oriented programming)Social classMereologyPattern languagePoint (geometry)Software frameworkConfiguration spaceCartesian coordinate systemAdditionInternet service providerComputer animationSource code
Software developerComputer configurationAdditionConfiguration spaceMobile appCartesian coordinate systemType theoryExtension (kinesiology)Social classPattern languageMiddlewareWeb pageCASE <Informatik>Reading (process)Operator (mathematics)Computer animationSource code
Software developerComputer configurationSocial classCASE <Informatik>Figurate numberComputer configurationExtension (kinesiology)Pattern languageMiddlewareLevel (video gaming)Cartesian coordinate systemTemplate (C++)Direction (geometry)Application service providerMobile appComputer animationSource code
Software developerAuthenticationFluid staticsDirectory serviceDefault (computer science)Computer fileComputing platformTemplate (C++)Source codeApplication service providerConnectivity (graph theory)Cartesian coordinate systemWeightComputer fileAuthenticationProper mapDirectory serviceTheoryWordObservational studyDifferent (Kate Ryan album)Process (computing)Identity managementDefault (computer science)EmailWindowSubject indexingRepresentation (politics)Electronic mailing listForm (programming)Domain nameAuthorizationMiddlewareRootDependent and independent variablesToken ringAdditionSource codeComputer animation
Software developerComputer fileFreewarePoint (geometry)MiddlewareError messageWeb browserDirectory serviceValidity (statistics)BuildingRootDependent and independent variablesSubject indexingWebsiteObservational studySource code
Software developerData centerRootObservational studyRoutingSubject indexingDefault (computer science)Mobile appComputer fileComputer animationSource code
Software developerDirectory serviceObservational studySubject indexingDefault (computer science)Object (grammar)Computer fileMiddlewareServer (computing)Point (geometry)Cartesian coordinate systemFluid staticsDatei-ServerRootComputer animationSource code
Software developerLemma (mathematics)PhysicalismSystem callRoutingLevel (video gaming)BitEndliche ModelltheorieServer (computing)Computer fileDefault (computer science)Computer configurationGroup actionDirectory serviceInternet service providerType theoryCartesian coordinate systemDifferent (Kate Ryan album)Module (mathematics)Point (geometry)Projective planeMobile appApplication service providerMiddlewareMessage passingDatei-ServerComputer animationSource code
Web pageException handlingSoftware developerError messageCodeTexture mappingIntegrated development environmentError messageMiddlewareRun time (program lifecycle phase)Web pageInformationSoftware frameworkDifferent (Kate Ryan album)Exception handlingNetwork topologySoftware developerProduct (business)TouchscreenLevel (video gaming)CodeMobile appTracing (software)Source code
Web pageError messageTexture mappingCodeSoftware developerWeb pageSoftware developerError messageProduct (business)MiddlewareLevel (video gaming)Different (Kate Ryan album)Mobile appException handlingContext awarenessSource code
Software developerPoint (geometry)Exception handlingLine (geometry)Software developerWeb pageShared memoryEmailHTTP cookieString (computer science)Query languageComputer animationSource code
Software developerInternet service providerCache (computing)Read-only memoryExtension (kinesiology)Category of beingAuthenticationGoogolFacebookTwitterWechselseitige InformationRun time (program lifecycle phase)Default (computer science)Web pageInformationMultiplication signPhysical systemRevision controlQuicksortMiddlewareDifferent (Kate Ryan album)State of matterHTTP cookieNuclear spaceEmailGame controllerSource codeDemo (music)Application service providerCache (computing)Mobile appServer (computing)WritingAuthenticationCategory of beingObject (grammar)Core dumpInternet service providerFigurate numberDot productComputer configurationForm (programming)FrequencyTwitterSemiconductor memoryOffice suiteCASE <Informatik>SequelSource code
Software developerAuthenticationNormed vector spaceCartesian coordinate systemComputer fileApplication service providerObject (grammar)Mobile appLoginInterface (computing)AuthenticationIntegrated development environmentComputer configurationInternet service providerMiddlewareBitAuthorizationContext awarenessWeb pageVotingComputer animationSource code
AuthenticationSoftware developerIdentity managementAbstractionMechanism designInternet service providerGame controllerSoftware testingContext awarenessConfiguration spaceQuicksortSampling (statistics)Server (computing)Multiplication signSoftware testingSource codeBit rateTask (computing)Inclusion mapWeb applicationSocial classInternet service providerIdentity managementUnit testingProjective planeContext awarenessWeightSystem administratorExecution unitEmailHTTP cookieRouter (computing)Integrated development environmentImplementationSign (mathematics)Repository (publishing)Information securityBuildingDependent and independent variablesInformationWeb pageCodeAuthenticationMiddlewareApplication service providerMultilaterationAuthorizationConfiguration spaceLoginCore dumpLatent heat
EmailDependent and independent variablesSoftware developerEquals signServer (computing)Order (biology)CountingDatabase transactionHost Identity ProtocolContext awarenessComputer configurationSocial classLengthGroup actionProcess (computing)LogicObject (grammar)SoftwareMessage passingProper mapEmailSoftware testingServer (computing)Dependent and independent variablesWeb 2.0Greatest elementComputer configurationGroup actionClient (computing)QuicksortTouchscreenArchaeological field surveyInternet service providerFlow separationExtension (kinesiology)Multiplication signCategory of beingComputer fileEndliche ModelltheorieCodeContext awarenessException handlingOperator (mathematics)Connectivity (graph theory)String (computer science)Event horizonSoftware developerWeb pageProcess (computing)Data dictionaryMereologyShared memoryStreaming mediaDifferent (Kate Ryan album)Point (geometry)FrustrationSet (mathematics)Order (biology)Boiling pointForcing (mathematics)Fluid staticsMiddlewareApplication service providerDefault (computer science)ExistenceState of matterMultiplicationMultilaterationSource codeComputer animation
Software developerFiber (mathematics)Software developerBlogException handlingWeb pageError messageBit rateRight angleLine (geometry)Existential quantificationCartesian coordinate systemCuboidQuicksortConfiguration spaceSelf-organizationServer (computing)Category of beingFunction (mathematics)Social classMiddlewareWeb applicationComputer clusterSource codeComputer animation
Transcript: English(auto-generated)
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 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 middleware 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, sorry, incoming request and there's an outgoing response and those two parts of a transaction get to visit each piece of middleware, but it is 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 an 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, authoriser, 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 authoriser drops one of these requests because someone is not authorised to post here, the logger would never see it,
right? Simple concept, but you can also get to 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 Korn.
Now, the reason I think this is important is because a lot of people compare middleware to high HTTP 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, and 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 actually 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. You can also improve performance. You might have seen some of the performance benchmarks on github.com slash ASP.net slash benchmarks. 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
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 wwwroot, that is the new public folder where files are served from an 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
and try to run this application, and if I go to the root 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. Oh, about ten lines. Up here it is. Thank you. This is so small, even on my screen.
All right. That devenvironment.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 requests, and it forwards those HTTP requests directly into my ASP.net 5 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 wwwroot, which is where you will point your virtual directory for ASP.net 5 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? Yes. 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 forward them along to, 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
host 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 start-up 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 this different request. There's also configure services where I can configure the IOC container, there'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 go 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. 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 sharper to generate a method just 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, lets 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 and 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 middleware in the pipeline. So even though I request index.html, doesn't matter what the request is going to be, they all end up in that piece of code that 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. What 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 before that happens I can do an app.use. So app.use is a little bit different. 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 coin, 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, console, let's do a 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.writeline 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, 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 fire 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
no output. That's interesting. Well, why wouldn't it do that? Hmm, hmm, hmm. 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. 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 meatier 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 where you place the code when you care about the incoming request. So, if you want to check authorisation 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 D, control K D to do some formatting. Let's try
that out. I hit run without 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 actually 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 piece, a little bit of, there is a little bit of magic
inside of ASP.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? It did. So one of the things that I'll make more clear a little bit later is that the order of these are registered is the order in which things will happen. So if this is the first piece of middleware, the request will always go through
here. Yep. And if I ran with the debugger again, you would see that. You 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, cursor slipped away on me, is it will look for a method
on an 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.request.path starts with the
following URL segment slash greeting. This is one way to do it. Then I went 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, use middleware.
I say I want to use this type, greeting middleware. And I'm not going to pass in any additional parameters right now. I just want to see if this thing will work. So
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 will 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. Fingers are still not functioning this week. Options dot path
equals slash greeting. Options dot text equals a configured greeting. Exclamation 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 for sharper to hide that off into a private field, and now down here starts
with segments, I would want to use options dot, sorry, underscore options, path, and display the text options dot 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 methods. Let's call it greeting extensions. It's not really going to matter what the name of the class is if I typo it. This is going to be a
public method, 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 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 run into 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 subapplication 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 IAS 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 will 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-IAS-Windows
auth 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 will 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.aspnet.static files package. It 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 a 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. And you might be saying, well, this is a lot of trouble just to serve static files. It 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 got my index.html. That's good.
What about if I go to the root of the website? That's running at other hello. So maybe we should differentiate between this to a little cleaner. 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 files 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. And 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, you're 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 wwwroot. 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 wwwroot and one that will serve things from node modules. So this first call to app.useFileServer, that will serve things from wwwroot, www. 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 is 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 wwwroot,
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. Making 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. 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 when something bad happens. But if you can think about what this piece of middleware will do, think about what it looks like inside.
It will 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 loaded, 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 anytime 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.NET MVC 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'll probably just use an accept cores attribute that you can put on a controller.
This one's sort of, yeah, it goes everywhere. That's in the microsoft.aspnet.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 you want to 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 iDistributed, or something that implements iDistributed 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 session ID,
and then take that cookie to go to the caching source and retrieve the session information that I've 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 Redis or SQL Server and have a distributed cache.
It just works. There's no more ASP.net state server, but there is Redis that you can use. What about authentication? I know Brock and Dom 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 5 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 5 where you configure things like that particular policy
is just going to make sure that we have an authenticated user. That's a 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 username. I just wanted to make sure they weren't anonymous users. So app.useProtectFolder, that path, that policy name,
what does the middleware look like? Just like the greeting middleware that we talked about, it takes a 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. And, 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 challenge the user and say you have to be an admin or you have to be authenticated.
MVC has a piece of middleware. Now you might have a pretty good idea of what useMVC would do. That piece of middleware will look at an incoming request, it will hand things off to the iRouter implementations and ASP.net MVC and basically ask the MVC router,
is this a request you're going to handle? If MVC 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 MVC 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 context we think, oh, that's going to be hard, right?
But there is a package, microsoft.aspnet.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 that 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 are 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've 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 and they might have written out some headers and they might have written out a large part of the body in a stream operation. So 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. So 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 HTTP context.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 this. 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 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 this one in static files is 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 registerForDispose 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. 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.
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 new application and do a full web application. You'll be able to look at that.
and say I need all of this stuff and you might rip out a piece or two here and there. And I think that's for most line of business applications would be somewhere along that line.
Will you need to write your own middleware? I see things like right now there were 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.