{"action":"created","comment":{"url":"https://api.github.com/repos/aspnet/Docs/pulls/comments/54856373","id":54856373,"diff_hunk":"@@ -1,8 +1,576 @@\n-.. include:: /../common/stub-topic.txt\n+Migrating HTTP Modules to Middleware\n+====================================\n \n-|stub-icon| Migrating HTTP Modules to Middleware\n-======================================================\n+By `Matt Perdeck`_\n \n-.. include:: /../common/stub-notice.txt\n+This article shows how to migrate existing ASP.NET `HTTP modules and handlers <https://msdn.microsoft.com/en-us/library/bb398986.aspx>`_ to ASP.NET 5 :ref:`middleware <fundamentals-middleware>`.\n \n-.. _issue: https://github.com/aspnet/Docs/issues/98\n+.. contents:: In this article:\n+  :local:\n+  :depth: 1\n+\n+Handlers and modules revisited\n+------------------------------\n+Before proceeding to ASP.NET 5 middleware, let's first recap how HTTP modules and handlers work: \n+\n+.. image:: http-modules/_static/moduleshandlers.png\n+\n+Handlers are:\n+\t* Classes that implement `IHttpHandler <https://msdn.microsoft.com/en-us/library/system.web.ihttphandler(v=vs.100).aspx>`_\n+\t* Used to handle requests with a given file name or extension, such as *.report*\n+\t* `Configured <https://msdn.microsoft.com/en-us/library/46c5ddfy(v=vs.100).aspx>`__ in the *web.config*\n+\n+Modules are:\n+\t* Classes that implement `IHttpModule <https://msdn.microsoft.com/en-us/library/system.web.ihttpmodule(v=vs.100).aspx>`_\n+\t* Invoked for every request\n+\t* Able to stop further processing of a request\n+\t* Able to add to the HTTP response, or create their own\n+\t* `Configured <https://msdn.microsoft.com/en-us/library/ms227673(v=vs.100).aspx>`__ in the web.config\n+\n+**The order in which modules process incoming requests is determined by:**\n+\n+\t1.\tThe `application life cycle <https://msdn.microsoft.com/en-us/library/ms227673(v=vs.100).aspx>`_, \n+\t\twhich is a series events fired by ASP.NET\n+\t\t- \n+\t\t`BeginRequest <https://msdn.microsoft.com/en-us/library/system.web.httpapplication.beginrequest(v=vs.100).aspx>`_,\n+\t\t`AuthenticateRequest <https://msdn.microsoft.com/en-us/library/system.web.httpapplication.authenticaterequest(v=vs.100).aspx>`_, etc.\n+\t\tEach module can create a handler for one or more events.\n+\n+\t2. When handling the same event, the order in which they are configured in the web.config.\n+\n+In addition to modules, you can add handlers for the life cycle events to your *Global.asax.cs* file. These handlers run after the handlers in the configured modules.\n+\n+From handlers and modules to middleware\n+---------------------------------------\n+Middleware is simpler than HTTP modules and handlers:\n+    * Modules, handlers, Global.asax.cs, web.config (except for IIS configuration) and the application life cycle are gone\n+    * The roles of both modules and handlers have been taken over by middleware\n+    * Middleware is configured using code instead of in the web.config\n+    * :ref:`Pipeline branching <middleware-run-map-use>` lets you send requests to specific middleware, based on not only the URL but also on request headers, etc.\n+\n+Middleware is very similar to modules:\n+\t* Invoked in principle for every request\n+\t* Able to stop further processing of a request\n+\t* Able to create their own HTTP response\n+\n+Middleware and modules are processed in a different order:\n+\t* While the request is going up the pipeline, middleware is processed in the order in which it is inserted into the request pipeline, similar to modules\n+\t* But while the response is going back to the browser, middleware is processed in the reverse order\n+\n+.. image:: http-modules/_static/middleware.png\n+\n+Migrating module code to middleware\n+------------------------------------\n+An existing HTTP module will look similar to this:\n+\n+.. literalinclude:: http-modules/sample/Asp.Net4/Asp.Net4/Modules/MyModule.cs\n+\t:language: c#\n+\t:linenos:\n+\t:emphasize-lines: 6, 8, 24, 31\n+\n+As shown in the :doc:`../fundamentals/middleware` page,\n+an ASP.NET 5 middleware is simply a class that exposes an ``Invoke`` method taking an ``HttpContext`` and returning a ``Task``. Your new middleware will look like this:\n+\n+.. _http-modules-usemiddleware:\n+\n+.. literalinclude:: http-modules/sample/Asp.Net5/src/Asp.Net5/Middleware/MyMiddleware.cs\n+\t:language: c#\n+\t:linenos:\n+\t:emphasize-lines: 9, 13, 20, 24, 28, 30, 32\n+\n+The middleware template used here is the same as that shown in the section on \n+:ref:`writing middleware <middleware-writing-middleware>`.\n+\n+The `MyMiddlewareExtensions` helper class makes it easier to configure your middleware in your ``Startup`` class. \n+The ``UseMyMiddleware`` method adds your middleware class to the request pipeline. Services required by the middleware get injected in the middleware's constructor.\n+\n+Maybe your module sometimes terminates the request, for example if the user is not authorized:\n+\n+.. literalinclude:: http-modules/sample/Asp.Net4/Asp.Net4/Modules/MyTerminatingModule.cs\n+\t:language: c#\n+\t:linenos:\n+\t:emphasize-lines: 9-13\n+\t:lines: 18-31\n+\t:dedent: 8\n+\n+A middleware handles this by simply not calling ``Invoke`` on the next middleware in the pipeline. Keep in mind that this does not \n+fully terminate the request, because previous middlewares will still be invoked when the response makes it way back through the pipeline\n+to the browser.\n+\n+.. literalinclude:: http-modules/sample/Asp.Net5/src/Asp.Net5/Middleware/MyTerminatingMiddleware.cs\n+\t:language: c#\n+\t:linenos:\n+\t:emphasize-lines: 7, 8\n+\t:lines: 16-26\n+\t:dedent: 8\n+\n+When you migrate your module's functionality to your new middleware, you may find that your code doesn't compile because the ``HttpContext`` class \n+has changed greatly in ASP.NET 5. `Later on <#migrating-to-the-new-httpcontext>`_, you'll see how to migrate to the new ASP.NET 5 HttpContext.\n+\n+Migrating module insertion into the request pipeline\n+-----------------------------------------------------\n+HTTP modules are typically added to the request pipeline using web.config:\n+\n+.. literalinclude:: http-modules/sample/Asp.Net4/Asp.Net4/Web.config\n+\t:language: xml\n+\t:linenos:\n+\t:emphasize-lines: 6\n+\t:lines: 1-3, 29-30, 33, 40, 48, 105\n+\n+Convert this by `adding your new middleware <../fundamentals/middleware.html#creating-a-middleware-pipeline-with-iapplicationbuilder>`_\n+to the request pipeline in your ``Startup`` class:\n+\n+.. literalinclude:: http-modules/sample/Asp.Net5/src/Asp.Net5/Startup.cs\n+\t:language: c#\n+\t:linenos:\n+\t:lines: 1-2, 12-15, 46-48, 54-58, 105, 109, 110\n+\t:emphasize-lines: 12\n+\n+The exact spot in the pipeline where you insert your new middleware depends on the event \n+that it handled as a module (``BeginRequest``, ``EndRequest``, etc.) and its order in your list of modules in your web.config.\n+\n+However, as you saw there is no more application life cycle in ASP.NET 5","path":"aspnet/migration/http-modules.rst","position":137,"original_position":137,"commit_id":"1769f379c9a06c9b339fd83280a5db3cdcfd2c30","original_commit_id":"24681cbe6fa7d5dff5444aeb86f79fbd18dade25","user":{"login":"mperdeck","id":1974601,"avatar_url":"https://avatars.githubusercontent.com/u/1974601?v=3","gravatar_id":"","url":"https://api.github.com/users/mperdeck","html_url":"https://github.com/mperdeck","followers_url":"https://api.github.com/users/mperdeck/followers","following_url":"https://api.github.com/users/mperdeck/following{/other_user}","gists_url":"https://api.github.com/users/mperdeck/gists{/gist_id}","starred_url":"https://api.github.com/users/mperdeck/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mperdeck/subscriptions","organizations_url":"https://api.github.com/users/mperdeck/orgs","repos_url":"https://api.github.com/users/mperdeck/repos","events_url":"https://api.github.com/users/mperdeck/events{/privacy}","received_events_url":"https://api.github.com/users/mperdeck/received_events","type":"User","site_admin":false},"body":"done","created_at":"2016-03-03T09:45:31Z","updated_at":"2016-03-03T09:45:31Z","html_url":"https://github.com/aspnet/Docs/pull/1010#discussion_r54856373","pull_request_url":"https://api.github.com/repos/aspnet/Docs/pulls/1010","_links":{"self":{"href":"https://api.github.com/repos/aspnet/Docs/pulls/comments/54856373"},"html":{"href":"https://github.com/aspnet/Docs/pull/1010#discussion_r54856373"},"pull_request":{"href":"https://api.github.com/repos/aspnet/Docs/pulls/1010"}}},"pull_request":{"url":"https://api.github.com/repos/aspnet/Docs/pulls/1010","id":60087396,"html_url":"https://github.com/aspnet/Docs/pull/1010","diff_url":"https://github.com/aspnet/Docs/pull/1010.diff","patch_url":"https://github.com/aspnet/Docs/pull/1010.patch","issue_url":"https://api.github.com/repos/aspnet/Docs/issues/1010","number":1010,"state":"open","locked":false,"title":"Mperdeck/http modules","user":{"login":"mperdeck","id":1974601,"avatar_url":"https://avatars.githubusercontent.com/u/1974601?v=3","gravatar_id":"","url":"https://api.github.com/users/mperdeck","html_url":"https://github.com/mperdeck","followers_url":"https://api.github.com/users/mperdeck/followers","following_url":"https://api.github.com/users/mperdeck/following{/other_user}","gists_url":"https://api.github.com/users/mperdeck/gists{/gist_id}","starred_url":"https://api.github.com/users/mperdeck/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mperdeck/subscriptions","organizations_url":"https://api.github.com/users/mperdeck/orgs","repos_url":"https://api.github.com/users/mperdeck/repos","events_url":"https://api.github.com/users/mperdeck/events{/privacy}","received_events_url":"https://api.github.com/users/mperdeck/received_events","type":"User","site_admin":false},"body":"After some delays, here is my pull request for the \"Migrating HTTP Modules to Middleware\" chapter.","created_at":"2016-02-21T13:15:49Z","updated_at":"2016-03-03T09:45:31Z","closed_at":null,"merged_at":null,"merge_commit_sha":"c1744756054753c5ad9a3ee628567ab0421751d1","assignee":{"login":"danroth27","id":1874516,"avatar_url":"https://avatars.githubusercontent.com/u/1874516?v=3","gravatar_id":"","url":"https://api.github.com/users/danroth27","html_url":"https://github.com/danroth27","followers_url":"https://api.github.com/users/danroth27/followers","following_url":"https://api.github.com/users/danroth27/following{/other_user}","gists_url":"https://api.github.com/users/danroth27/gists{/gist_id}","starred_url":"https://api.github.com/users/danroth27/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danroth27/subscriptions","organizations_url":"https://api.github.com/users/danroth27/orgs","repos_url":"https://api.github.com/users/danroth27/repos","events_url":"https://api.github.com/users/danroth27/events{/privacy}","received_events_url":"https://api.github.com/users/danroth27/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/aspnet/Docs/pulls/1010/commits","review_comments_url":"https://api.github.com/repos/aspnet/Docs/pulls/1010/comments","review_comment_url":"https://api.github.com/repos/aspnet/Docs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/aspnet/Docs/issues/1010/comments","statuses_url":"https://api.github.com/repos/aspnet/Docs/statuses/1769f379c9a06c9b339fd83280a5db3cdcfd2c30","head":{"label":"mperdeck:mperdeck/http-modules","ref":"mperdeck/http-modules","sha":"1769f379c9a06c9b339fd83280a5db3cdcfd2c30","user":{"login":"mperdeck","id":1974601,"avatar_url":"https://avatars.githubusercontent.com/u/1974601?v=3","gravatar_id":"","url":"https://api.github.com/users/mperdeck","html_url":"https://github.com/mperdeck","followers_url":"https://api.github.com/users/mperdeck/followers","following_url":"https://api.github.com/users/mperdeck/following{/other_user}","gists_url":"https://api.github.com/users/mperdeck/gists{/gist_id}","starred_url":"https://api.github.com/users/mperdeck/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mperdeck/subscriptions","organizations_url":"https://api.github.com/users/mperdeck/orgs","repos_url":"https://api.github.com/users/mperdeck/repos","events_url":"https://api.github.com/users/mperdeck/events{/privacy}","received_events_url":"https://api.github.com/users/mperdeck/received_events","type":"User","site_admin":false},"repo":{"id":50315775,"name":"Docs","full_name":"mperdeck/Docs","owner":{"login":"mperdeck","id":1974601,"avatar_url":"https://avatars.githubusercontent.com/u/1974601?v=3","gravatar_id":"","url":"https://api.github.com/users/mperdeck","html_url":"https://github.com/mperdeck","followers_url":"https://api.github.com/users/mperdeck/followers","following_url":"https://api.github.com/users/mperdeck/following{/other_user}","gists_url":"https://api.github.com/users/mperdeck/gists{/gist_id}","starred_url":"https://api.github.com/users/mperdeck/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mperdeck/subscriptions","organizations_url":"https://api.github.com/users/mperdeck/orgs","repos_url":"https://api.github.com/users/mperdeck/repos","events_url":"https://api.github.com/users/mperdeck/events{/privacy}","received_events_url":"https://api.github.com/users/mperdeck/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mperdeck/Docs","description":"Documentation for ASP.NET 5","fork":true,"url":"https://api.github.com/repos/mperdeck/Docs","forks_url":"https://api.github.com/repos/mperdeck/Docs/forks","keys_url":"https://api.github.com/repos/mperdeck/Docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mperdeck/Docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mperdeck/Docs/teams","hooks_url":"https://api.github.com/repos/mperdeck/Docs/hooks","issue_events_url":"https://api.github.com/repos/mperdeck/Docs/issues/events{/number}","events_url":"https://api.github.com/repos/mperdeck/Docs/events","assignees_url":"https://api.github.com/repos/mperdeck/Docs/assignees{/user}","branches_url":"https://api.github.com/repos/mperdeck/Docs/branches{/branch}","tags_url":"https://api.github.com/repos/mperdeck/Docs/tags","blobs_url":"https://api.github.com/repos/mperdeck/Docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mperdeck/Docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mperdeck/Docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/mperdeck/Docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mperdeck/Docs/statuses/{sha}","languages_url":"https://api.github.com/repos/mperdeck/Docs/languages","stargazers_url":"https://api.github.com/repos/mperdeck/Docs/stargazers","contributors_url":"https://api.github.com/repos/mperdeck/Docs/contributors","subscribers_url":"https://api.github.com/repos/mperdeck/Docs/subscribers","subscription_url":"https://api.github.com/repos/mperdeck/Docs/subscription","commits_url":"https://api.github.com/repos/mperdeck/Docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/mperdeck/Docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/mperdeck/Docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/mperdeck/Docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/mperdeck/Docs/contents/{+path}","compare_url":"https://api.github.com/repos/mperdeck/Docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mperdeck/Docs/merges","archive_url":"https://api.github.com/repos/mperdeck/Docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mperdeck/Docs/downloads","issues_url":"https://api.github.com/repos/mperdeck/Docs/issues{/number}","pulls_url":"https://api.github.com/repos/mperdeck/Docs/pulls{/number}","milestones_url":"https://api.github.com/repos/mperdeck/Docs/milestones{/number}","notifications_url":"https://api.github.com/repos/mperdeck/Docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mperdeck/Docs/labels{/name}","releases_url":"https://api.github.com/repos/mperdeck/Docs/releases{/id}","deployments_url":"https://api.github.com/repos/mperdeck/Docs/deployments","created_at":"2016-01-25T00:35:35Z","updated_at":"2016-01-25T00:35:43Z","pushed_at":"2016-03-03T06:28:46Z","git_url":"git://github.com/mperdeck/Docs.git","ssh_url":"git@github.com:mperdeck/Docs.git","clone_url":"https://github.com/mperdeck/Docs.git","svn_url":"https://github.com/mperdeck/Docs","homepage":null,"size":33812,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"aspnet:master","ref":"master","sha":"aedc10fbcd4916eda7fcb2d0fa7464d866e8a8c1","user":{"login":"aspnet","id":6476660,"avatar_url":"https://avatars.githubusercontent.com/u/6476660?v=3","gravatar_id":"","url":"https://api.github.com/users/aspnet","html_url":"https://github.com/aspnet","followers_url":"https://api.github.com/users/aspnet/followers","following_url":"https://api.github.com/users/aspnet/following{/other_user}","gists_url":"https://api.github.com/users/aspnet/gists{/gist_id}","starred_url":"https://api.github.com/users/aspnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aspnet/subscriptions","organizations_url":"https://api.github.com/users/aspnet/orgs","repos_url":"https://api.github.com/users/aspnet/repos","events_url":"https://api.github.com/users/aspnet/events{/privacy}","received_events_url":"https://api.github.com/users/aspnet/received_events","type":"Organization","site_admin":false},"repo":{"id":28239455,"name":"Docs","full_name":"aspnet/Docs","owner":{"login":"aspnet","id":6476660,"avatar_url":"https://avatars.githubusercontent.com/u/6476660?v=3","gravatar_id":"","url":"https://api.github.com/users/aspnet","html_url":"https://github.com/aspnet","followers_url":"https://api.github.com/users/aspnet/followers","following_url":"https://api.github.com/users/aspnet/following{/other_user}","gists_url":"https://api.github.com/users/aspnet/gists{/gist_id}","starred_url":"https://api.github.com/users/aspnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aspnet/subscriptions","organizations_url":"https://api.github.com/users/aspnet/orgs","repos_url":"https://api.github.com/users/aspnet/repos","events_url":"https://api.github.com/users/aspnet/events{/privacy}","received_events_url":"https://api.github.com/users/aspnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/aspnet/Docs","description":"Documentation for ASP.NET 5","fork":false,"url":"https://api.github.com/repos/aspnet/Docs","forks_url":"https://api.github.com/repos/aspnet/Docs/forks","keys_url":"https://api.github.com/repos/aspnet/Docs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aspnet/Docs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aspnet/Docs/teams","hooks_url":"https://api.github.com/repos/aspnet/Docs/hooks","issue_events_url":"https://api.github.com/repos/aspnet/Docs/issues/events{/number}","events_url":"https://api.github.com/repos/aspnet/Docs/events","assignees_url":"https://api.github.com/repos/aspnet/Docs/assignees{/user}","branches_url":"https://api.github.com/repos/aspnet/Docs/branches{/branch}","tags_url":"https://api.github.com/repos/aspnet/Docs/tags","blobs_url":"https://api.github.com/repos/aspnet/Docs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aspnet/Docs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aspnet/Docs/git/refs{/sha}","trees_url":"https://api.github.com/repos/aspnet/Docs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aspnet/Docs/statuses/{sha}","languages_url":"https://api.github.com/repos/aspnet/Docs/languages","stargazers_url":"https://api.github.com/repos/aspnet/Docs/stargazers","contributors_url":"https://api.github.com/repos/aspnet/Docs/contributors","subscribers_url":"https://api.github.com/repos/aspnet/Docs/subscribers","subscription_url":"https://api.github.com/repos/aspnet/Docs/subscription","commits_url":"https://api.github.com/repos/aspnet/Docs/commits{/sha}","git_commits_url":"https://api.github.com/repos/aspnet/Docs/git/commits{/sha}","comments_url":"https://api.github.com/repos/aspnet/Docs/comments{/number}","issue_comment_url":"https://api.github.com/repos/aspnet/Docs/issues/comments{/number}","contents_url":"https://api.github.com/repos/aspnet/Docs/contents/{+path}","compare_url":"https://api.github.com/repos/aspnet/Docs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aspnet/Docs/merges","archive_url":"https://api.github.com/repos/aspnet/Docs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aspnet/Docs/downloads","issues_url":"https://api.github.com/repos/aspnet/Docs/issues{/number}","pulls_url":"https://api.github.com/repos/aspnet/Docs/pulls{/number}","milestones_url":"https://api.github.com/repos/aspnet/Docs/milestones{/number}","notifications_url":"https://api.github.com/repos/aspnet/Docs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aspnet/Docs/labels{/name}","releases_url":"https://api.github.com/repos/aspnet/Docs/releases{/id}","deployments_url":"https://api.github.com/repos/aspnet/Docs/deployments","created_at":"2014-12-19T17:38:02Z","updated_at":"2016-03-02T16:47:19Z","pushed_at":"2016-03-03T06:28:47Z","git_url":"git://github.com/aspnet/Docs.git","ssh_url":"git@github.com:aspnet/Docs.git","clone_url":"https://github.com/aspnet/Docs.git","svn_url":"https://github.com/aspnet/Docs","homepage":null,"size":41540,"stargazers_count":404,"watchers_count":404,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":655,"mirror_url":null,"open_issues_count":146,"forks":655,"open_issues":146,"watchers":404,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/aspnet/Docs/pulls/1010"},"html":{"href":"https://github.com/aspnet/Docs/pull/1010"},"issue":{"href":"https://api.github.com/repos/aspnet/Docs/issues/1010"},"comments":{"href":"https://api.github.com/repos/aspnet/Docs/issues/1010/comments"},"review_comments":{"href":"https://api.github.com/repos/aspnet/Docs/pulls/1010/comments"},"review_comment":{"href":"https://api.github.com/repos/aspnet/Docs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/aspnet/Docs/pulls/1010/commits"},"statuses":{"href":"https://api.github.com/repos/aspnet/Docs/statuses/1769f379c9a06c9b339fd83280a5db3cdcfd2c30"}}}}