Asp разумное использование объекта session


Содержание

Избегайте кэшировать медленные компоненты в объектах Application или Session. Разумное использование объекта Session

АККОМПАНИРОВАТЬ accompagner ,> нем. akkompanieren . 1 . дипл. Приложить к чему-л., спроводить чем-л. (какую-л . посылку, отправление) . Я тот экстракт письмом своим не аккомпанировал. Кантемир Реляц. 2 172.

2. расш. Сопровождать кого-, что-л., быть дополнением к чему-л. Спинат, растение самое здоровое и для всякого желудка годное.. аккомпанирует все нарядные блюда. 1809. Гримо Прихотник 60. Однажды меня с Сазоновым (он мне всегда аккомпанирует в Ватикане) заперли. Гальберг Письма 57. Одни злословят по привычке, другие аккомпанируют. Ростопчин Ох, французы 114. Дежурный по полку ротмистр доказал, что ему хотелось есть и что аппетит у него богатырский, да и мы все аккомпанировали ему недурно, нечего сказать, не отказываясь от лафита и д»икема, которым, гостеприимный хозяин наполнял наши стаканы. В. П. Бурнашев Восп. // РА 1872 1839.

3. 1690. Лексис. муз. Сопровождать аккомпанементом. Акомпанировать своему голосу . Кн. муз. 52. Играть соло или аккомпанировать в сих концертах. Финдейз. 171. <Отец> играл на Виолончеле, и всегда акомпанировал наши Дуо. ММ 3 14. Он же Куликов фортепианами и арфою аккомпанирует. <Шарманщик> аккомпанирует вальс Ланнера свистками и трелями. Григорович Петерб. шарманщик. Он аккомпанировал Вьетану и многим певцам. Римский-Корс. Летопись. // РР 1970 1 60. || Припевать, подпевать . Но не было ли, спрашивает он, в вашем пении монотонии? Было, отвечает целомудренная супруга; но в финале все хорошо акомпанировали. Зритель 1 121. Хватайко поет и все акомпанируют: бери, большой тут нет науки. Капнист Ябеда 85.

4. перен. Сопровождая что-л., создавать определенный фон. БАС-2. Шепот продолжался, и ему аккомпанировал смущенно-счастливый смех. Мам.- Сиб. Черты из жизни Пепко. Собаки, смирно лежавшие у ворот, не выдерживали <визга поросят> и принялись аккомпанировать громким лаем и воем. А. Осипович Мечтатели. // ОЗ 1881 8 1 462. Лишь папа лесничий Дрожжинин шумно ел суточные щи, да мама для этикета аккомпанировала, едва разжимая строгие губы. Аксенов Затоварен. бочкотара. // РР 1970 3 60. — Лекс. Ян.1803: акомпанировать; Соколов 1834: акомпаниров а/ ть; Даль: акомпаниров а/ ть; САН 1933: аккомпан и/ ровать; Сл. 18: аккомпанировать 1734 (ако- 1792).

Исторический словарь галлицизмов русского языка. — М.: Словарное издательство ЭТС http://www.ets.ru/pg/r/dict/gall_dict.htm . Николай Иванович Епишкин [email protected] . 2010 .

Смотреть что такое «аккомпанировать» в других словарях:

АККОМПАНИРОВАТЬ — (фр. accompagner). Сопровождать пение игрою на каком либо музыкальном инструменте. Словарь иностранных слов, вошедших в состав русского языка. Чудинов А.Н., 1910. АККОМПАНИРОВАТЬ франц. accompagner. Сопровождать пение игрою на каком либо… … Словарь иностранных слов русского языка

аккомпанировать — См … Словарь синонимов

аккомпанировать — и устарелое аккомпанировать … Словарь трудностей произношения и ударения в современном русском языке

АККОМПАНИРОВАТЬ — АККОМПАНИРОВАТЬ, рую, руешь; несовер., кому. Исполнять аккомпанемент. А. на рояле. Толковый словарь Ожегова. С.И. Ожегов, Н.Ю. Шведова. 1949 1992 … Толковый словарь Ожегова

АККОМПАНИРОВАТЬ — кого или что (сонату) чем, на чем, муз., франц. вторить, сопровождать, подголашивать, подголосить, подыгрывать; держать другой, согласный голос. Аккомпанирование ср., ·длит. аккомпанировка жен., ·об. действие по гл., вторенье, подголоска,… … Толковый словарь Даля

аккомпанировать — (иноск. шут.) вторить, делать что в подражание другому, совместно с ним (намек на сопровождение пения или одного инструмента игрою одного или многих инструментов) Ср. Я издавна солист и аккомпанемента не ожидаю, один пью. Лесков. На ножах. 1,… … Большой толково-фразеологический словарь Михельсона

Аккомпанировать — несов. неперех. 1. Сопровождать игрой на музыкальном инструменте или на музыкальных инструментах сольную вокальную или инструментальную партию, основную тему или мелодию музыкального произведения. 2. перен. Создавать определённый фон, сопровождая … Современный толковый словарь русского языка Ефремовой

аккомпанировать — аккомпанировать, аккомпанирую, аккомпанируем, аккомпанируешь, аккомпанируете, аккомпанирует, аккомпанируют, аккомпанируя, аккомпанировал, аккомпанировала, аккомпанировало, аккомпанировали, аккомпанируй, аккомпанируйте, аккомпанирующий,… … Формы слов

аккомпанировать — аккомпан ировать, рую, рует … Русский орфографический словарь

аккомпанировать — (I), аккомпани/рую, руешь, руют … Орфографический словарь русского языка

Книги

  • Учись аккомпанировать на 6-струнной гитаре. От романсов к року и джазу , Манилов В.. В книге вы найдете необходимые сведения об аккордах, их последовательностях и способах усложнения партии ритм-гитары, о стандартной аппликатуре и типовых ритмических моделях различных жанров…

Inside the ASP.NET Worker Process, there are two thread pools. The worker thread pool handles all incoming requests and the I/O Thread pool handles the I/O (accessing the file system, web services and databases, etc.). Each App Domain has its own thread pool and the number of operations that can be queued to the thread pool is limited only by available memory; however, the thread pool limits the number of threads that can be active in the process simultaneously.

So how many threads are there in these thread pools? I had always assumed that the number of threads varies from machine to machine – that ASP.NET and IIS were carefully and cleverly balancing the number of available threads against available hardware, but that is simply not the case. The fact is that ASP.NET installs with a fixed, default number of threads to play with: the 1.x Framework defaults to just 20 worker threads (per CPU) and 20 I/O threads (per CPU). The 2.0 Framework defaults to 100 threads in each pool, per CPU. Now this can be increased by adding some new settings to the machine.config file. The default worker thread limit was raised to 250 per CPU and 1000 I/O threads per CPU with the .NET 2.0 SP1 and later Frameworks. 32 bit windows can handle about 1400 concurrent threads, 64 bit windows can handle more, though I don’t have the figures.

In a normal (synchronous) Page Request, a single worker thread handles the entire request from the moment it is received until the completed page is returned to the browser. When the I/O operation begins, a thread is pulled from the I/O thread pool, but the worker thread is idle until that I/O thread returns. So, if your page load event fires off one or more I/O operations, then that main worker thread could be idle for 1 or more seconds and in that time, it could have serviced hundreds of additional incoming page requests.

Source : Microsoft Tech Ed 2007 DVD: Web 405 «Building Highly Scalable ASP.NET Web Sites by Exploiting Asynchronous Programming Models» by Jeff Prosise.

So long as the number of concurrent requests does not exceed the number of threads available in the pool, all is well. But when you are building enterprise level applications, the thread pool can become depleted under heavy load, and remember by default, heavy load is more than just 200 simultaneous requests assuming a dual CPU Server.

When this happens, new requests are entered into the request queue (and the users making the requests watch that little hour glass spin and consider trying another site). ASP.NET will allow the request queue to grow only so big before it starts to reject requests at which point it starts returning Error 503, Service Unavailable.

If you are not aware of this “Glass Ceiling of Scalability”, this is a perplexing error – one that never happened in testing and may not be reproducible in your test environment, as it only happens under extreme load.

Asynchronous Programming models in ASP.NET

To solve this problem, ASP.NET provides four asynchronous programming models. Asyncronous Pages, Asyncronous HttpHandlers, Asyncronous HttpModules and Asynchronous Web Services. The only one that is well documented and reasonably well known is the asynchronous Web Services model. Since there is quite a lot of documentation on that, and since in future web services should be implemented using the Windows Communication Foundation, we shall concentrate only on the other three.

Let’s begin with the first asynchronous programming model, Asynchronous Pages.

Asynchronous Pages

Source : Microsoft Tech Ed 2007 DVD: Web 405 «Building Highly Scalable ASP.NET Web Sites by Exploiting Asynchronous Programming Models» by Jeff Prosise.

To make a page Asynchronous, we insert what we refer to as an “Async Point” into that page’s lifecycle, which you can see in green on the right. We need to write and register with ASP.NET a pair of Begin and End Events. At the appropriate point in the page’s lifecycle, ASP.NET will call our begin method. In the begin method, we will launch an asynchronous I/O operation, for example an asynchronous database query, and we will immediately return from the begin method. As soon as we return, ASP.NET will drop the thread that was assigned to that request back into the thread pool where it may service hundreds or even thousands of additional page requests while we wait for our I/O operation to complete.

As you’ll see, when we get to the sample code, we return from our begin method an IAsyncResult Interface , through which we can signal ASP.NET when the async operation that we launched has completed. It is when we do that, that ASP.NET reaches back into the thread pool, pulls out a second worker thread and calls our end method, and then allows the processing of that request to resume as normal.

So, from ASP.NET’s standpoint, it is just a normal request, but it is processed by 2 different threads; and that will bring up a few issues that we’ll need to discuss in a few moments.

Now, none of this was impossible with the 1.1 framework, but it was a lot of extra work, and you lost some of the features of ASP.NET in the process. The beauty of the 2.0 and later frameworks is that this functionality is built right into the Http pipeline, and so for the most part, everything works in the asynchronous page just as it did in the synchronous one.

In order to create an Asynchronous page, you need to include the Async=”True” attribute in the page directive of your .aspx file. That directive tells the ASP.NET engine to implement an additional Interface on the derived page class which lets ASP.NET know at runtime that this is an asynchronous page.

What happens if you forget to set that attribute? Well, the good news is that the code will still run just fine, but it will run synchronously, meaning that you d >

The second thing we need to do in order to create an asynchronous page is to register Begin and End Events. There are 2 ways to register these events. The first way is to use a new method introduced in ASP.NET 2.0 called AddOnPreRenderCompleteAsync:

using System; using System.Net; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; public partial >The second way is to use RegisterAsyncTask:

using System; using System.Net; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; public partial >http://www.asyncassassin.com/asyncassassin/image.axd?picture=2008%2f12%2fSlide3.JPG» ); private HttpWebRequest request; vo > Begin async operation and return IAsyncResult return request.BeginGetResponse(cb, state); > void EndAsyncOperation(IAsyncResult ar) < // Get results of async operation HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(ar); Label1.Text = String .Format(" Image at <0>is <1:n0>bytes» , response.ResponseUri, response.ContentLength); > void TimeoutAsyncOperation(IAsyncResult ar) < // Called if async operation times out (@ Page AsyncTimeout) Label1.Text = " Data temporarily unavailable" ; >>

These methods can be called anywhere in the page’s lifecycle before the PreRender event, and are typically called from the Page_Load event or from the click event of a button during a postback. By the way, you can register these methods from within a UserControl , as long as that control is running on a page that has set the async = true attribute. Again, if it runs on a page without that attribute, the code will still run just fine, but it will run synchronously.

As you can see from just these simple examples, building asynchronous pages is more difficult than building synchronous ones. I’m not going to lie to you. And real world use of these techniques is even more complicated – there is no Business Logic or data layer in the examples above. I don’t want you to leave here believing that you need to make every page asynchronous. You don’t. What I recommend, is doing surgical strikes. Identify that handful of pages in your application that perform the lengthiest I/O and consider converting those into asynchronous pages. The cool thing about this, is that it can improve not only scalability, but also performance, because when you are not holding onto the threads, new requests get into the pipeline faster, they spend less time waiting in that application request queue out there. So, users are happier because pages that they would have had to wait on before – even the ones you have not converted to asynchronous pages, but which might have been delayed while threads were idle, will now load faster. What’s more, as you’ll see in a moment, using RegisterAsyncTask will allow you to perform I/O operations in parallel, which may also improve performance. Having said that, making pages asynchronous is not really about improving performance, it is about improving scalability – making sure that we use the threads in the thread pool as efficiently as we possibly can.

Now I’m sure you are wondering why there are two ways, what the differences are between them, and when you should choose one over the other. Well, there are 3 important differences between AddOnPreRenderCompleteAsync and RegisterAsyncTask .

  1. As we have seen, RegisterAsyncTask allows you to specify a timeout method. It is important to note that the timeout value you specify in the Page Directive of your .aspx page is the timeout for ALL asynchronous tasks the page is performing, not 5 secs per async task — all async tasks must be competed within 5 seconds, so be sure to allow enough time here.
  2. If you use AddOnPreRenderCompleteAsync , you may find that some things that worked before, no longer work. For example, if you are using User.Identity.Name in your code to get the authenticated username in order to personalize a page. If this method is called by the first thread, it will work fine. But if you call it on the second thread – in your End method or any of the events that fire after the end method, User.Identity.Name will be null . This is because as a Request travels through the ASP.NET Http Pipeline, it is accompanied by an object of type HttpContext that basically encapsulates all of the information that ASP.NET knows about that request. When you use AddOnPreRenderCompleteAsync , ASP.NET does not take the extra time to map everything in that context object from thread one to thread two. That’s why User.Identity.Name does not work in thread two. In fact, you will often find that HttpContext.Current is null in thread two. However, if you use RegisterAsyncTask , ASP.Net DOES map everything in that context from thread one to thread two. It does take a few microseconds longer to do this, but it will make your life considerably easier.
  3. The third difference is probably the most important of all. AddOnPreRenderCompleteAsync is a quick and easy way of making a page asynchronous and works well if you have a simple page that needs to perform only 1 asynchronous I/O operation. In real life, a page often needs to perform multiple database queries, or grab data from a webservice and pass it to a database, or something like that. The cool thing about RegisterAsyncTask is that it allows you to quickly and easily queue up multiple Async I/O operations. The last argument is a Boolean value that allows you to specify whether each task can run in parallel. Sometimes, you need to wait for one data call to complete in order to send that data somewhere else, but other times you may need to get data from multiple, unrelated sources and this allows you to fetch them all at the same time, instead of one after the other.

Source : Microsoft Tech Ed 2007 DVD: Web 405 «Building Highly Scalable ASP.NET Web Sites by Exploiting Asynchronous Programming Models» by Jeff Prosise.

N-Tier Applications

OK. So I expect some of you are thinking “But what if I have a data access layer in my application? My pages can’t go directly to the database, they have to go through that data access layer, or they have to go through my BLL, which calls the Data Access Layer.”

Well, ideally, you should simply add the asynchronous methods to your DAL. If you wrote the DAL yourself or have access to its source code, you should add the Begin and End methods to it. Adding the asynchronous methods to your DAL is the best, most scalable solution and doesn’t change the example code much at all: Instead of calling begin and end methods defined inside the page class, you simply call MyDAL.Begin … or MyBll.Begin … when you call RegisterAsyncTask or AddOnPreRenderAsync .

Unfortunately, neither Llblgen nor the Enterprise library (nor LINQ for that matter) supports asynchronous data calls natively. However, I believe that you can modify the generated code in llblgen to enable asynchronous data calls. You could also crack open the source code of the Enterprise library and add the asynchronous methods yourself, but before you try, check to see if it has already been done .

Asynchronous HTTP Handlers

The 2 nd Asynchronous Programming model in ASP.NET is for HttpHandler s and has been around since .Net 1.x, but was not documented any better in version 2 than it was in version 1. Http Handlers are one of the two fundamental building blocks of ASP.NET, an http handler is an object that is built to handle http requests and convert them into http responses. For the most part, each handler corresponds to a file type. For example, there is a built in handler in ASP.NET that handles .aspx files. It is that handler that knows how to instantiate a control tree and send that tree to a rendering engine. The ASMX Handler knows how to decode SOAP and allows us to build web services.

Basically an HTTP Handler is just a class that implements the IHttpHandler interface , which consists of an IsResuable Boolean function and a ProcessRequest method which is the heart of an httphandler as its job is to turn a request into a response. The ProcessRequest method is passed an HttpContext Object containing all the data ASP.NET has collected about the request, as well as exposing the Session , Server , Request and Response objects that you are used to working with in page requests.

using System.Web; public + name); > public bool IsReusable < get < return true ; >> >

There are 2 ways to build them. One way is to add the class to your project and register it in the web.config . If you want to register it for any file extension not currently handled by ASP.NET, you would need to add that extension to IIS. The easier way is to deploy them as .ASHX files. The ASHX extension has already been registered in IIS, it is auto compiled, no changes are required in the web.config and performance is the same. Ok. So you know what they are and how to build one, when is an appropriate time to use one?

Handlers are commonly used to generate custom XML and RSS feeds, to unzip and render files stored as BLOB fields in the database including image files or logos, HTTP Handlers can also be used as the target of AJAX calls.

A common mistake that programmers new to .NET, especially those like myself who came from classic ASP or PHP, is to use the Page_Load event of a page to create a new http response. For example, before I learned about httphandlers , I would use the page load event to create an XML document or a dynamic PDF file and output it to the response stream with a response.End() to prevent the page continuing after I output my file. The problem with that approach is that you are executing a ton of code in ASP.NET that doesn’t need to execute. When ASP.NET sees that request come in, it thinks it is going to need to build and render a control tree. By pointing the link at the handler instead, you will gain a 10-20% performance increase every time that request is fetched, just because of the overhead you have reduced. Put simply, Http Handlers minimize the amount of code that executes in ASP.NET.

To implement an Asynchronous handler, you use the interface IHttpAsyncHandler , which adds BeginProcessRequest and EndProcessRequest methods. The threading works the same way as with an async page. After the begin method is called, the thread returns to the thread pool and handles other incoming requests until the I/O thread completes its work, at which point it grabs a new thread from the thread pool and completes the request.

Page.RegisterAsyncTask cannot be used here, so if you need to run multiple async tasks, you will need to implement your own IAsyncResult Interface and pass in your own callbacks to prevent the EndProcessRequest method being called before you have completed all your async operations.

Asynchronous HTTP Modules

HTTP Modules are another fundamental building block of ASP.NET. They don’t handle requests, instead they sit in the HTTP Pipeline where they have the power to review every request coming in and every response going out. Not only can they view them, but they can modify them as well. Many of the features of ASP.NET are implemented using httpmodules: authentication, Session State and Caching for example, and by creating your own HTTP Modules, you can extend ASP.NET in a lot of interesting ways. You could use an HTTP Module for example to add Google analytics code to all pages, or a custom footer. Logging is another common use of HTTP Modules.

E-Commerce web sites can take advantage of HTTP Modules by overriding the default behavior of the Session Cookie. By default, ASP.NET Session Cookies are only temporary, so if you use them to store shopping cart information, after 20 minutes of inactivity, or a browser shut down they are gone. You may have noticed that Amazon.com retains shopping cart information much longer: You could shut down your laptop, fly to Japan and when you restart and return to Amazon your items will still be there. If you wanted to do this in ASP.NET, you could waste a lot of time writing your own Session State Cookie Class, or you could write about 10 lines of code in the form of an HTTP Module that would intercept the cookie created by the Session Object before it gets to the browser, and modify it to make it a persistent cookie. So, there are lots and lots of practical uses for HTTP Modules.

An Http Module is nothing more than a class that implements the IHttpModule Interface , which involves an Init method for registering any and all events that you are interested in intercepting, and a dispose method for cleaning up any resources you may have used.

using System; using System.Web; public ); > public void Dispose() < >>

The events you can intercept in an HTTP Module are as shown below:

Source : Microsoft Tech Ed 2007 DVD: Web 405 «Building Highly Scalable ASP.NET Web Sites by Exploiting Asynchronous Programming Models» by Jeff Prosise.

Notice the HTTP Handler at the end there that converts the request into a response. These events will always fire in this order, in every request. The Authenticate Request event is the one fired by ASP.NET when a requested page requires authentication. It checks to see if you have an authentication cookie and if you do not, redirects the request to the login page. In the simple example, I was using that End Request event, which is the last one before the response is sent to the browser.

So, that is what HTTP Modules are for, and how they work. Why do we need an Asynchronous version? Well if you really want to see how scalable your application is, add an HTTP Module that makes a synchronous call to a webservice or a database. Since the event you register will be fired on every request, you will tie up an additional thread from the ASP.NET thread pool on every single request that is just waiting for these I/O processes to complete. So, if you write a synchronous HTTP Module that inserts a record into a database for every single request, and that insert takes 1 second, EVERY single request handled by your application will be delayed by 1 second. So if you need to do any type of I/O from within an HTTP Module, I recommend you make the calls asynchronously and if you are retrieving data, cache it!

To Register Async Event Handlers in an http module — In the Init method, simply register your begin and end methods using AddOnPreRequestHandlerExecuteAsync:

Error Handling while Multithreading

Errors can happen at any point during the execution of a command. When ASP.NET can detect errors before initiating the actual async operation, it will throw an exception from the begin method; this is very similar to the synchronous case in which you get the exceptions from a call to ExecuteReader or similar methods directly. This includes invalid parameters, bad state of related objects (no connection set for a SqlCommand , for example), or some connectivity issues (the server or the network is down, for example).

Now, once we send the operation to the server and return, ASP.NET doesn’t have any way to let you know if something goes wrong at the exact moment it happens. It cannot just throw an exception as there is no user code above it in the stack when doing intermediate processing, so you wouldn»t be able to catch an exception if it threw one. What happens instead is that ASP.NET stores the error information, and signals that the operation is complete. Later on, when your code calls the end method, ASP.NET detects that there was an error during processing and the exception is thrown.

The bottom line is that you need to be prepared to handle errors in both the begin and the end methods, so it is wise to wrap both events in a try – Catch block.

Conclusion

Now you have seen three of the asynchronous programming models ASP.NET has to offer, hopefully I have impressed upon you how important it is to at least consider using them when creating pages that do I/O if you expect those pages to be heavily trafficked. Remember you can also create asynchronous web services. I didn’t cover those here because there is pretty good documentation for that already.

The good thing about Asynchronous Programming models is that it enables us to build scalable and responsive applications that use minimal resources (threads/context switches).

What is the down side? Well it forces you to split the code into many callback methods, making it hard to read, confusing to debug and difficult for programmers unfamiliar with asynchronous programming to maintain.


With this in mind, whenever I add an asynchronous method to an object in the my projects, I also add a traditional Synchronous version. For example, if I had created a BeginUpdatexxx() method in the BLL, there would also be a traditional Updatexxx() method, so that if anyone else finds themselves having to use that object, they won’t be left scratching their heads, wondering “how on earth do I use that?”

Asynchronous command execution is a powerful extension to.NET. It enables new high-scalability scenarios at the cost of some extra complexity.

Об опасностях выполнения фоновых задач в ASP.NET. Он выделил три основных риска, связанных с запуском фонового процесса:

  1. Необработанное исключение в потоке, несвязанном с запросом, может снять процесс.
  2. Если запустить сайт в веб-ферме, то есть вероятность случайно завершить несколько экземпляров приложения, которое могло запустить несколько экземпляров одной и той же задачи одновременно.
  3. Домен приложения, в котором запущен сайт, по разным причинам может выгрузиться и снять фоновую задачу, запущенную в нем.

Конечно, можно написать собственный менеджер для управления фоновыми задачами. Но, вероятнее всего, Вы сделаете это неправильно. Никто не собирается оспаривать Ваши навыки разработчика. Просто создание подобного менеджера — это достаточно тонкая вещь. Да и зачем Вам это надо?

Есть множество отличных вариантов запуска задач в фоновом режиме. И не просто абстрактных методик, а готовых библиотек.

Какие-то ASP.NET приложения могут работать на Ваших собственных серверах под IIS, какие-то размещаться в Azure.

Для запуска фоновых задач можно выделить несколько вариантов:

HANGFIRE

Документация Hangfire действительно превосходна. Хотелось бы, чтобы каждый проект с открытым исходным кодом имел такую документацию.

Одной из самых эффектных функций Hangfire является встроенная аналитическая панель, которая позволяет просматривать расписания, выполняющиеся задания, успешные и неуспешно завершенные задания.

Hangfire позволяет легко определить задачи типа «запустить и забыть», информация о которых будет храниться в базе данных:

BackgroundJob.Enqueue(() => Console.WriteLine(«Fire-and-forget»));
Можно отсрочить выполнение задачи:

BackgroundJob.Schedule(() => Console.WriteLine(«Delayed»), TimeSpan.FromDays(1));
Или запустить задачу в CRON стиле

RecurringJob.AddOrUpdate(() => Console.Write(«Recurring»), Cron.Daily);
Работать с Hangfire очень удобно. Hangfire имеет хорошую документацию и обучающие руководства , основанные на реальных примерах.

Hangfire — это целая экосистема для работы с фоновыми задачами в ASP.NET приложениях.

Библиотеки доступны в виде открытых исходных кодов или Nuget пакетов.

Итоги (лично от себя)

Я уже знаю, что мне нужно запускать больше одного процесса, и работать процессы могут долго (ограничение в 90 секунд на завершение в QueueBackgroundWorkItem). FluentScheduler выглядит неплохо, но хотелось большего. Hangfire – отличное решение, но, вроде, сразу требует использования базы данных для хранения очереди задач. Да и не совсем там все бесплатно – есть и платная версия.

В итоге я пока выбрал Quartz.NET: вполне приличная документация, достаточное количество примеров, чтобы быстро начать использовать, а также расширяемый функционал, который можно добавлять по мере возрастания потребностей.

Если вы знаете другие библиотеки для запуска фоновых задач или имеете опыт решения подобных задач – делитесь в комментариях.

A thread is defined as the execution path of a program. Each thread defines a unique flow of control. If your application involves complicated and time consuming operations such as database access or some intense I/O operations, then it is often helpful to set different execution paths or threads, with each thread performing a particular job.

Threads are lightweight processes. One common example of use of thread is implementation of concurrent programming by modern operating systems. Use of threads saves wastage of CPU cycle and increases efficiency of an application.

So far we compiled programs where a single thread runs as a single process which is the running instance of the application. However, this way the application can perform one job at a time. To make it execute multiple tasks at a time, it could be divided into smaller threads.

In .Net, the threading is handled through the «System.Threading» namespace. Creating a variable of the System.Threading.Thread type allows you to create a new thread to start working with. It allows you to create and access individual threads in a program.

Creating Thread

A thread is created by creating a Thread object, giving its constructor a ThreadStart reference.

ThreadStart childthreat = new ThreadStart(childthreadcall);

Thread Life Cycle

The life cycle of a thread starts when an object of the System.Threading.Thread class is created and ends when the thread is terminated or completes execution.

Following are the various states in the life cycle of a thread:

The Unstarted State : It is the situation when the instance of the thread is created but the Start method is not called.

The Ready State : It is the situation when the thread is ready to execute and waiting CPU cycle.

The Not Runnable State : a thread is not runnable, when:

  • Sleep method has been called
  • Wait method has been called
  • Blocked by I/O operations

The Dead State : It is the situation when the thread has completed execution or has been aborted.

Thread Priority

The Priority property of the Thread class specifies the priority of one thread with respect to other. The .Net runtime selects the ready thread with the highest priority.

The priorities could be categorized as:

  • Above normal
  • Below normal
  • Highest
  • Lowest
  • Normal

Once a thread is created, its priority is set using the Priority property of the thread class.

Thread Properties & Methods

The Thread class has the following important properties:

Property Description
CurrentContext Gets the current context in which the thread is executing.
CurrentCulture Gets or sets the culture for the current thread.
CurrentPrinciple Gets or sets the thread»s current principal for role-based security.
CurrentThread Gets the currently running thread.
CurrentUICulture Gets or sets the current culture used by the Resource Manager to look up culture-specific resources at run time.
ExecutionContext Gets an ExecutionContext object that contains information about the various contexts of the current thread.
IsAlive Gets a value indicating the execution status of the current thread.
IsBackground Gets or sets a value indicating whether or not a thread is a background thread.
IsThreadPoolThread Gets a value indicating whether or not a thread belongs to the managed thread pool.
ManagedThreadId Gets a unique identifier for the current managed thread.
Name Gets or sets the name of the thread.
Priority Gets or sets a value indicating the scheduling priority of a thread.
ThreadState Gets a value containing the states of the current thread.

The Thread class has the following important methods:

Asp разумное использование объекта session

Веб-сервер автоматически создает объект Session для каждого пользователя, который обращается к asp-сценарию. С помощью объекта Session можно сохранять некоторую информацию в течение сеанса работы клиента. (О том, зачем это нужно, мы говорили, рассматривая использование ключиков Cookies). Работа с объектом Session основана на использовании cookies и невозможна, если браузер их не поддерживает. В отличие от cookies, сессия действует ограниченное время, по истечении которого объект Session уничтожается.

Илон Маск рекомендует:  Захват видео с камеры с помощью JavaScript и HTML5

Каждая сессия занимает приблизительно 10 Кб памяти (сверх самих данных, сохраненных в объекте Session) и немного замедляет выполнение всех запросов.

Причины завершения сессии

Истечение времени, установленного как значение свойства Timeout (по умолчанию — 20 минут), если в течение этого времени от клиента не поступает запросов на обновление страницы или загрузку нового документа.

Чтобы снизить объем серверной памяти, занятой приложением, имеет смысл устанавливать реальные значения длительности жизни объекта Session. Например, если пользователь, по Вашему мнению, не задержится на сайте дольше 5 минут, установите:

&lt% Session.Timeout = 5 %&gt

Объект Session уничтожен из asp-сценария (методом Abandon()):

&lt % Session.Abandon(); %&gt

Сбой web-сервера или его остановка администратором.

В этом случае уничтожаются все сессии. Удаление (или запрет) cookies в браузере. Изменение файла Global.asa.

Идентификатор сессии

При первом обращении браузера к web-серверу (точнее, к одному из asp-сценариев) web-сервер создает уникальный, присущий только этому браузеру идентификатор сессии (SessionID); этот идентификатор и используется для того, чтобы web-сервер мог «узнать» этот браузер при последующих обращениях.

SessionID сохраняется браузером (как cookie) пока не произойдет одно из перечисленных выше событий, в результате которых объект Session будет уничтожен.

Идентификатор сессии является свойством объекта Session, обращение к нему выглядит, например, так:

Переменные объекта Session

Объект Session позволяет сохранять информацию с помощью скалярных переменных или объектов. Например, сохраним в документе first.asp имя и возраст клиента, а также его login:

В этом же документе разместим ссылку на другой документ данного приложения (назовем его second.asp)? где предусмотрим обращение к переменным сессии:

С помощью объекта Session можно, например, запомнить свойства браузера и в зависимости от них формировать тот или иной вариант web-страницы. При этом отпадает необходимость анализировать свойства браузера в каждом документе. Например, пользователям с низким разрешением экрана можно предложить текстовую версию страницы:

Задание 1. Создайте в одном директории два asp-файла, связанных взаимными гиперссылками. В каждом из этих файлов предусмотрите вывод значения идентификатора сессии.

Задание 2. Создайте документ с формой для ввода имени и фамилии пользователя, а также его возраста. Пусть данные от формы передаются asp-сценарию, который запоминает их как переменные сессии. Создайте еще два asp-файла, связанных с эти файлом гиперссылками. В каждом из asp-файлов предусмотрите вывод значений переменных сессии.

Недостатки Session

Сессии имеют несколько недостатков, которые проявляются в следующих случаях:

при использовании на сильно загруженных сайтах (с сотнями запрашиваемых страниц в секунду или тысячами пользователей одновременно) происходит большой расход серверной памяти;

при горизонтальном масштабировании, т.е. использовании нескольких серверов для распределения нагрузки и обеспечения отказоустойчивости при сбоях;

при использовании фреймов: ASP гарантирует, что в любой момент времени выполняется только один запрос от Session. Поэтому страницы загружаются во фреймы не одновременно, а последовательно, и пользователю приходится долго ждать полной загрузки.

ASP без объекта Session

ASP позволяет создавать asp-документы, не формирующие объекта Session. Для этого нужно использовать директиву:

&lt%@ EnableSessionState=False %&gt

Объект Application

Как отмечалось выше, сессии не охватывают все задействованные в веб-приложении серверы — созданный на сервере объект Session доступен только на нем. Это означает, что при использовании сессий на мультисерверном веб-сайте, обязательно должно происходить перенаправление запросов каждого пользователя на тот сервер, на котором существует сессия этого пользователя. Это называется «застреванием» пользователя на сервере (или «липкой» сессиейsticky session).


Частично эту проблему можно решить за счет использования объекта Application. В отличие от объекта Session, позволяющего «закреплять» данные за конкретным пользователем, объект Application позволяет создавать переменные, доступные одновременно всем пользователям web-приложения. Под приложением понимаются все .asp-файлы в виртуальной директории и всех ее поддиректориях.

Поскольку объект Application доступен (shared) более чем одному пользователю, в нем предусотрено два метода — Lock (заблокировать) и Unlock (разблокировать). Они используются, чтобы сразу несколько пользователей не могли изменить содержимое общедоступных переменных одновременно.

Состояние сеанса и приложения в ASP.NET Core Session and app state in ASP.NET Core

HTTP — это протокол без отслеживания состояния. HTTP is a stateless protocol. Без дополнительных действий HTTP-запросы являются независимыми сообщениями, которые не сохраняют значения пользователя или состояние приложения. Without taking additional steps, HTTP requests are independent messages that don’t retain user values or app state. В этой статье описывается несколько подходов для сохранения данных пользователя и состояния приложения между запросами. This article describes several approaches to preserve user data and app state between requests.

Управление состоянием State management

Состояние можно сохранить несколькими способами. State can be stored using several approaches. Эти способы обсуждается ниже в данном разделе. Each approach is described later in this topic.

Способ хранения данных Storage approach Механизм хранения Storage mechanism
Файлы «cookie» Cookies Файлы cookie HTTP (могут содержать данные, сохраненные с помощью кода приложения на стороне сервера) HTTP cookies (may include data stored using server-side app code)
Состояние сеанса Session state Файлы cookie HTTP и код приложения на стороне сервера HTTP cookies and server-side app code
TempData TempData Файлы cookie HTTP или состояние сеанса HTTP cookies or session state
Строки запросов Query strings Строки запросов HTTP HTTP query strings
Скрытые поля Hidden fields Поля формы HTTP HTTP form fields
HttpContext.Items HttpContext.Items Код приложения на стороне сервера Server-side app code
Кэш Cache Код приложения на стороне сервера Server-side app code
Введение зависимостей Dependency Injection Код приложения на стороне сервера Server-side app code

Файлы cookie хранят данные между запросами. Cookies store data across requests. Так как файлы cookie отправляются с каждым запросом, их размер нужно свести к минимуму. Because cookies are sent with every request, their size should be kept to a minimum. В идеальном случае файл cookie должен содержать лишь идентификатор, а сами данные хранятся в приложении. Ideally, only an identifier should be stored in a cookie with the data stored by the app. Большинство браузеров позволяют использовать файлы cookie размером до 4096 байт. Most browsers restrict cookie size to 4096 bytes. Для каждого домена доступно лишь ограниченное число файлов cookie. Only a limited number of cookies are available for each domain.

Так как файлы cookie могут быть незаконно изменены, их нужно проверять в приложении. Because cookies are subject to tampering, they must be validated by the app. Файлы cookie могут удаляться пользователем и имеют ограниченный срок хранения на клиентах. Cookies can be deleted by users and expire on clients. Тем не менее файлы cookie обычно являются самым надежным способом хранения данных на стороне клиента. However, cookies are generally the most durable form of data persistence on the client.

Файлы cookie часто используются для персонализации, когда содержимое настраивается под известного пользователя. Cookies are often used for personalization, where content is customized for a known user. В большинстве случаев пользователь проходит только идентификацию, а не проверку подлинности. The user is only identified and not authenticated in most cases. Файл cookie может хранить имя пользователя, имя учетной записи или уникальный идентификатор пользователя (например, GUID). The cookie can store the user’s name, account name, or unique user ID (such as a GUID). Затем можно использовать файл cookie для доступа к личным настройкам пользователя, таким как цвет фона на веб-сайте. You can then use the cookie to access the user’s personalized settings, such as their preferred website background color.

Помните об Общем регламенте по защите данных в ЕС (GDPR) при создании файлов cookie и решении вопросов с конфиденциальностью. Be mindful of the European Union General Data Protection Regulations (GDPR) when issuing cookies and dealing with privacy concerns. Дополнительные сведения см. в разделе Общий регламент по защите данных (GDPR), принятый в ЕС, в ASP.NET Core. For more information, see General Data Protection Regulation (GDPR) support in ASP.NET Core.

Состояние сеанса Session state

Состояние сеанса — это сценарий ASP.NET Core для хранения пользовательских данных, когда пользователь находится в веб-приложении. Session state is an ASP.NET Core scenario for storage of user data while the user browses a web app. Состояние сеанса использует хранилище, обслуживаемое приложением, для сохранения данных между запросами от клиента. Session state uses a store maintained by the app to persist data across requests from a client. Данные сеанса поддерживаются кэшем и считаются временными, — сайт должен работать и без данных сеанса. The session data is backed by a cache and considered ephemeral data—the site should continue to function without the session data. Критически важные данные приложения должны храниться в пользовательской базе данных и кэшироваться в сеансе только в качестве оптимизации производительности. Critical application data should be stored in the user database and cached in session only as a performance optimization.

Сеанс не поддерживается в приложениях SignalR, так как хаб SignalR может выполняться независимо от контекста HTTP. Session isn’t supported in SignalR apps because a SignalR Hub may execute independent of an HTTP context. Например, это может произойти, если хаб поддерживает длительный запрос на опрос открытым, когда время существования контекста HTTP для запроса уже истекло. For example, this can occur when a long polling request is held open by a hub beyond the lifetime of the request’s HTTP context.

ASP.NET Core сохраняет состояние сеанса, предоставляя клиенту файл cookie, содержащий идентификатор сеанса, который отправляется в приложение вместе с каждым запросом. ASP.NET Core maintains session state by providing a cookie to the client that contains a session ID, which is sent to the app with each request. Приложение использует этот идентификатор для получения данных сеанса. The app uses the session ID to fetch the session data.

Состояние сеанса реагирует на события следующим образом: Session state exhibits the following behaviors:

  • Так как файл cookie сеанса относится к конкретному браузеру, обеспечить общий доступ к сеансам из разных браузеров невозможно. Because the session cookie is specific to the browser, sessions aren’t shared across browsers.
  • Файлы cookie сеанса удаляются при завершении сеанса браузера. Session cookies are deleted when the browser session ends.
  • Если получен файл cookie для просроченного сеанса, создается сеанс, использующий этот же файл. If a cookie is received for an expired session, a new session is created that uses the same session cookie.
  • Пустые сеансы не сохраняются — в сеансе должно быть хотя бы одно значение, чтобы его можно быть сохранить между запросами. Empty sessions aren’t retained—the session must have at least one value set into it to persist the session across requests. Если сеанс не сохраняется, для каждого нового запроса создается новый идентификатор сеанса. When a session isn’t retained, a new session ID is generated for each new request.
  • Приложение хранит сеанс некоторое время после последнего запроса. The app retains a session for a limited time after the last request. Приложение устанавливает время ожидания сеанса или использует значение по умолчанию, равное 20 минутам. The app either sets the session timeout or uses the default value of 20 minutes. Состояние сеанса оптимально подходит для сохранения пользовательских данных, относящихся к определенному сеансу, которые не требуется хранить бессрочно для нескольких сеансов. Session state is ideal for storing user data that’s specific to a particular session but where the data doesn’t require permanent storage across sessions.
  • Данные сеанса удаляются при вызове реализации ISession.Clear или когда истекает срок действия сеанса. Session data is deleted either when the ISession.Clear implementation is called or when the session expires.
  • Не существует механизма по умолчанию, который бы информировал код приложения о том, что браузер клиента закрыт или файл cookie сеанса удален или просрочен на клиенте. There’s no default mechanism to inform app code that a client browser has been closed or when the session cookie is deleted or expired on the client.
  • Шаблоны ASP.NET Core MVC и Razor Pages поддерживают общий регламент по защите данных (GDPR). The ASP.NET Core MVC and Razor pages templates include support for General Data Protection Regulation (GDPR). Файлы cookie для состояния сеанса не помечаются как основные по умолчанию, поэтому состояние сеанса недоступно, если отслеживание разрешено посетителем сайта. Session state cookies aren’t marked essential by default, so session state isn’t functional unless tracking is permitted by the site visitor. Дополнительные сведения можно найти по адресу: Поддержка Общий регламент по защите данных (GDPR) в ASP.NET Core. For more information, see Поддержка Общий регламент по защите данных (GDPR) в ASP.NET Core.

Не храните конфиденциальные данные в состоянии сеанса. Don’t store sensitive data in session state. Пользователь может не закрывать браузер и очистить файл cookie сеанса. The user might not close the browser and clear the session cookie. Некоторые браузеры сохраняют файлы cookie сеанса в нескольких окнах браузера. Some browsers maintain valid session cookies across browser windows. Сеанс может быть не ограничен одним пользователем — следующий пользователь продолжит использовать приложение с тем же файлом cookie сеанса. A session might not be restricted to a single user—the next user might continue to browse the app with the same session cookie.

Поставщик кэша в памяти хранит данные сеанса в памяти сервера, содержащего приложение. The in-memory cache provider stores session data in the memory of the server where the app resides. В сценарии с фермой серверов: In a server farm scenario:

  • Используйте прикрепленные сеансы для привязки сеанса к конкретному экземпляру приложения на отдельном сервере. Use sticky sessions to tie each session to a specific app instance on an individual server. Служба приложений Azure использует маршрутизацию запросов приложений (ARR), чтобы прикрепленные сеансы создавались по умолчанию. Azure App Service uses Application Request Routing (ARR) to enforce sticky sessions by default. Однако прикрепленные сеансы могут негативно повлиять на масштабируемость и усложнить обновление веб-приложений. However, sticky sessions can affect scalability and complicate web app updates. Лучше использовать распределенные кэши SQL Server или Redis, для которых прикрепленные сеансы не требуются. A better approach is to use a Redis or SQL Server distributed cache, which doesn’t require sticky sessions. Дополнительные сведения можно найти по адресу: Распределенное кэширование в ASP.NET Core. For more information, see Распределенное кэширование в ASP.NET Core.
  • Файл cookie сеанса шифруется через IDataProtector. The session cookie is encrypted via IDataProtector. Необходимо правильно настроить защиту данных, чтобы читать файлы cookie сеанса на каждом компьютере. Data Protection must be properly configured to read session cookies on each machine. Дополнительные сведения см. статьях Защита данных в ASP.NET Core и Key storage providers in ASP.NET Core (Поставщики хранилища ключей в ASP.NET Core). For more information, see Защита данных в ASP.NET Core and Key storage providers.

Настройка состояния сеанса Configure session state

Пакет Microsoft.AspNetCore.Session, который входит в метапакет Microsoft.AspNetCore.App, предоставляет ПО промежуточного слоя для управления состоянием сеанса. The Microsoft.AspNetCore.Session package, which is included in the Microsoft.AspNetCore.App metapackage, provides middleware for managing session state. Чтобы включить сеанс ПО промежуточного слоя для сеансов, Startup должен содержать: To enable the session middleware, Startup must contain:

  • Любой из кэшей памяти IDistributedCache, Any of the IDistributedCache memory caches. при этом реализация IDistributedCache используется в качестве резервного хранилища для сеанса. The IDistributedCache implementation is used as a backing store for session. Дополнительные сведения можно найти по адресу: Распределенное кэширование в ASP.NET Core. For more information, see Распределенное кэширование в ASP.NET Core.
  • Вызов AddSession в ConfigureServices . A call to AddSession in ConfigureServices .
  • Вызов UseSession в Configure . A call to UseSession in Configure .

Следующий код показывает, как настроить поставщик сеансов в памяти с реализацией в памяти IDistributedCache по умолчанию: The following code shows how to set up the in-memory session provider with a default in-memory implementation of IDistributedCache :

Порядок ПО промежуточного слоя важен. The order of middleware is important. В предыдущем примере исключение InvalidOperationException возникает при вызове UseSession после UseMvc . In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc . Дополнительные сведения см. в разделе Порядок расположения ПО промежуточного слоя. For more information, see Middleware Ordering.

После настройки состояния сеанса доступно свойство HttpContext.Session. HttpContext.Session is available after session state is configured.

Невозможно получить доступ к HttpContext.Session до вызова UseSession . HttpContext.Session can’t be accessed before UseSession has been called.

Невозможно создать новый сеанс с новым файлом cookie сеанса после того, как приложение начинает запись в поток ответа. A new session with a new session cookie can’t be created after the app has begun writing to the response stream. Исключение записывается в журнал веб-сервера и не отображается в браузере. The exception is recorded in the web server log and not displayed in the browser.

Асинхронная загрузка состояния сеанса Load session state asynchronously

Поставщик сеансов по умолчанию в ASP.NET Core загружает запись сеанса из резервного хранилища IDistributedCache в асинхронном режиме только при явном вызове метода ISession.LoadAsync перед методами TryGetValue, Set или Remove. The default session provider in ASP.NET Core loads session records from the underlying IDistributedCache backing store asynchronously only if the ISession.LoadAsync method is explicitly called before the TryGetValue, Set, or Remove methods. Если LoadAsync не вызывается первым, базовая запись сеанса загружается синхронно, что может негативно повлиять на производительность. If LoadAsync isn’t called first, the underlying session record is loaded synchronously, which can incur a performance penalty at scale.

Чтобы принудительно использовать этот режим в приложениях, используйте для реализаций DistributedSessionStore и DistributedSession оболочку из версий, которые выдают исключение, когда метод LoadAsync не вызывается перед TryGetValue , Set или Remove . To have apps enforce this pattern, wrap the DistributedSessionStore and DistributedSession implementations with versions that throw an exception if the LoadAsync method isn’t called before TryGetValue , Set , or Remove . Зарегистрируйте версии оболочки в контейнере служб. Register the wrapped versions in the services container.

Параметры сеанса Session options

Чтобы переопределить значения по умолчанию для сеанса, используйте SessionOptions. To override session defaults, use SessionOptions.

Параметр Option ОПИСАНИЕ Description
Файл cookie Cookie Определяет параметры, используемые для создания файлов cookie. Determines the settings used to create the cookie. Параметр Name по умолчанию имеет значение SessionDefaults.CookieName ( .AspNetCore.Session ). Name defaults to SessionDefaults.CookieName ( .AspNetCore.Session ). Параметр Path по умолчанию имеет значение SessionDefaults.CookiePath ( / ). Path defaults to SessionDefaults.CookiePath ( / ). Параметр SameSite по умолчанию имеет значение SameSiteMode.Lax ( 1 ). SameSite defaults to SameSiteMode.Lax ( 1 ). Параметр HttpOnly по умолчанию имеет значение true . HttpOnly defaults to true . Параметр IsEssential по умолчанию имеет значение false . IsEssential defaults to false .
IdleTimeout IdleTimeout IdleTimeout указывает, как долго сеанс может быть неактивным, прежде чем его содержимое отбрасывается. The IdleTimeout indicates how long the session can be idle before its contents are abandoned. Каждый доступ к сеансу сбрасывает время ожидания. Each session access resets the timeout. Этот параметр применяется только к содержимому сеанса, а не к файлу cookie. This setting only applies to the content of the session, not the cookie. Значение по умолчанию — 20 минут. The default is 20 minutes.
IOTimeout IOTimeout Максимальный период загрузки сеанса из хранилища или его сохранения обратно в хранилище. The maximum amount of time allowed to load a session from the store or to commit it back to the store. Этот параметр может применяться только к асинхронным операциям. This setting may only apply to asynchronous operations. Время ожидания можно отключить с помощью InfiniteTimeSpan. This timeout can be disabled using InfiniteTimeSpan. Значение по умолчанию — 1 минута. The default is 1 minute.

Сеанс использует файл cookie для отслеживания и идентификации запросов в одном браузере. Session uses a cookie to track and identify requests from a single browser. По умолчанию этот файл cookie называется .AspNetCore.Session и использует путь / . By default, this cookie is named .AspNetCore.Session , and it uses a path of / . Так как по умолчанию файл cookie не указывает домен, он остается недоступным для клиентского сценария на странице (так как HttpOnly по умолчанию имеет значение true ). Because the cookie default doesn’t specify a domain, it isn’t made available to the client-side script on the page (because HttpOnly defaults to true ).

Чтобы переопределить файл cookie по умолчанию для сеанса, используйте SessionOptions : To override cookie session defaults, use SessionOptions :

Приложение использует свойство IdleTimeout, чтобы определить, как долго сеанс может оставаться неактивным до сброса его содержимого в кэше сервера. The app uses the IdleTimeout property to determine how long a session can be idle before its contents in the server’s cache are abandoned. Это свойство не зависит от срока действия файла cookie. This property is independent of the cookie expiration. Каждый запрос, проходящий через ПО промежуточного слоя сеанса, сбрасывает это время ожидания. Each request that passes through the Session Middleware resets the timeout.

Состояние сеанса является неблокирующим. Session state is non-locking. Когда два запроса пытаются изменить содержимое сеанса, последний из них переопределяет первый. If two requests simultaneously attempt to modify the contents of a session, the last request overrides the first. Session реализован в виде согласованного сеанса, что означает, что все содержимое хранится вместе. Session is implemented as a coherent session, which means that all the contents are stored together. Когда два запроса пытаются изменить разные значения сеанса, последний запрос может переопределить изменения, внесенные первым. When two requests seek to modify different session values, the last request may override session changes made by the first.

Установка и получение значений сеанса Set and get Session values

Получить доступ к состоянию сеанса можно через класс Razor Pages PageModel или класс MVC Controller со свойством HttpContext.Session. Session state is accessed from a Razor Pages PageModel class or MVC Controller class with HttpContext.Session. Оно является реализацией ISession. This property is an ISession implementation.

Реализация ISession предоставляет несколько методов расширения для задания и извлечения значений типа integer и string. The ISession implementation provides several extension methods to set and retrieve integer and string values. Методы расширения находятся в пространстве имен Microsoft.AspNetCore.Http (добавьте оператор using Microsoft.AspNetCore.Http; , чтобы получить доступ к методам расширения), когда проект ссылается на пакет Microsoft.AspNetCore.Http.Extensions. The extension methods are in the Microsoft.AspNetCore.Http namespace (add a using Microsoft.AspNetCore.Http; statement to gain access to the extension methods) when the Microsoft.AspNetCore.Http.Extensions package is referenced by the project. Оба пакета входят в метапакет Microsoft.AspNetCore.App. Both packages are included in the Microsoft.AspNetCore.App metapackage.

Методы расширения ISession : ISession extension methods:

В следующем примере извлекается значение сеанса для ключа IndexModel.SessionKeyName ( _Name в примере приложения) на странице Razor Pages: The following example retrieves the session value for the IndexModel.SessionKeyName key ( _Name in the sample app) in a Razor Pages page:

В следующем примере показано, как задать, а затем получить значения integer и string: The following example shows how to set and get an integer and a string:

Все данные сеанса должны быть сериализованы, чтобы использовать сценарий-распределенного кэша даже при использовании кэша в памяти. All session data must be serialized to enable a distributed cache scenario, even when using the in-memory cache. Предоставляются минимальные сериализаторы строки и числа (см. методы и методы расширения ISession). Minimal string and number serializers are provided (see the methods and extension methods of ISession). Сложные типы должны быть сериализованы пользователем с помощью другого механизма, например JSON. Complex types must be serialized by the user using another mechanism, such as JSON.

Добавьте приведенные ниже методы расширения, чтобы задавать и получать сериализуемые объекты: Add the following extension methods to set and get serializable objects:

Следующий пример показывает, как задать и получить сериализуемый объект с помощью методов расширения: The following example shows how to set and get a serializable object with the extension methods:

TempData TempData

ASP.NET Core предоставляет TempData Razor Pages или TempData контроллера. ASP.NET Core exposes the Razor Pages TempData or Controller TempData. Это свойство хранит данные до тех пор, пока они не будут прочитаны в другом запросе. This property stores data until it’s read in another request. Для проверки данных без удаления можно использовать методы Keep(String) и Peek(String) в конце запроса. Keep(String) and Peek(string) methods can be used to examine the data without deletion at the end of the request. Keep() помечает все элементы в словаре для хранения. Keep() marks all items in the dictionary for retention. TempData особенно удобно использовать для перенаправления, когда данные требуются для нескольких запросов. TempData is particularly useful for redirection when data is required for more than a single request. TempData реализуется поставщиками TempData , например, с помощью файлов cookie или состояния сеанса. TempData is implemented by TempData providers using either cookies or session state.

Примеры TempData TempData samples

Рассмотрим следующую страницу, которая создает клиент: Consider the following page that creates a customer:

На следующей странице отображается TempData[«Message»] : The following page displays TempData[«Message»] :

В предыдущей разметке в конце запроса TempData[«Message»] не удаляется, так как используется Peek . In the preceding markup, at the end of the request, TempData[«Message»] is not deleted because Peek is used. На обновляемой странице отображается TempData[«Message»] . Refreshing the page displays TempData[«Message»] .

Следующая разметка похожа на приведенный выше код, но в ней используется Keep для сохранения данных в конце запроса: The following markup is similar to the preceding code, but uses Keep to preserve the data at the end of the request:

При переходе между страницами IndexPeek и IndexKeep TempData[«Message»] не удаляется. Navigating between the IndexPeek and IndexKeep pages won’t delete TempData[«Message»] .

Следующий код отображает TempData[«Message»] , но в конце запроса TempData[«Message»] удаляется: The following code displays TempData[«Message»] , but at the end of the request, TempData[«Message»] is deleted:

Поставщики TempData TempData providers

Поставщик TempData, основанный на файлах cookie, используется по умолчанию для хранения TempData в файлах cookie. The cookie-based TempData provider is used by default to store TempData in cookies.

Данные в файле cookie шифруются с помощью IDataProtector, кодируются с помощью Base64UrlTextEncoder, а затем фрагментируются. The cookie data is encrypted using IDataProtector, encoded with Base64UrlTextEncoder, then chunked. Так как файл cookie фрагментируется, ограничение на размер одного такого файла, заданное в ASP.NET Core 1.x, не применяется. Because the cookie is chunked, the single cookie size limit found in ASP.NET Core 1.x doesn’t apply. Данные файла cookie не сжимаются, так как сжатие зашифрованных данных может привести к проблемам с безопасностью, например атакам CRIME и BREACH. The cookie data isn’t compressed because compressing encrypted data can lead to security problems such as the CRIME and BREACH attacks. Дополнительные сведения на поставщике TempData, основанном на файлах cookie, см. в разделе CookieTempDataProvider. For more information on the cookie-based TempData provider, see CookieTempDataProvider.

Выбор поставщика TempData Choose a TempData provider

Выбор поставщика TempData включает в себя несколько аспектов: Choosing a TempData provider involves several considerations, such as:

  1. Приложение уже использует состояние сеанса? Does the app already use session state? Если это так, использование поставщика TempData для состояния сеанса не требует от приложения никаких дополнительных издержек (кроме объема данных). If so, using the session state TempData provider has no additional cost to the app (aside from the size of the data).
  2. Приложение использует TempData лишь ограниченно, для сравнительно небольших объемов данных (до 500 байт)? Does the app use TempData only sparingly for relatively small amounts of data (up to 500 bytes)? Если это так, поставщик TempData на основе файлов cookie незначительно увеличивает издержки для каждого запроса, переносящего TempData. If so, the cookie TempData provider adds a small cost to each request that carries TempData. В противном случае поставщик TempData для состояния сеанса удобно использовать, чтобы устранить круговой обход большого объема данных в каждом запросе до полного использования TempData. If not, the session state TempData provider can be beneficial to avoid round-tripping a large amount of data in each request until the TempData is consumed.
  3. Приложение выполняется на ферме серверов на нескольких серверах? Does the app run in a server farm on multiple servers? Если это так, не требуется дополнительная настройка для использования поставщика TempData для файлов cookie, за исключением защиты данных (см. статьи Защита данных в ASP.NET Core и Key storage providers in ASP.NET Core (Поставщики хранилища ключей в ASP.NET Core)). If so, there’s no additional configuration required to use the cookie TempData provider outside of Data Protection (see Защита данных в ASP.NET Core and Key storage providers).

Большинство веб-клиентов (например, веб-браузеры) налагают ограничение на максимальный размер каждого файла cookie и (или) общее количество таких файлов. Most web clients (such as web browsers) enforce limits on the maximum size of each cookie, the total number of cookies, or both. При использовании поставщика TempData на основе файлов cookie убедитесь, что приложение не нарушает эти ограничения. When using the cookie TempData provider, verify the app won’t exceed these limits. Учитывайте общий объем данных. Consider the total size of the data. Учитывайте увеличение размеров файла cookie в результате шифрования и фрагментирования. Account for increases in cookie size due to encryption and chunking.

Настройка поставщика TempData Configure the TempData provider

Поставщик TempData на основе файлов cookie включен по умолчанию. The cookie-based TempData provider is enabled by default.

Чтобы включить поставщик TempData на основе сеанса, используйте метод расширения AddSessionStateTempDataProvider: To enable the session-based TempData provider, use the AddSessionStateTempDataProvider extension method:

Порядок ПО промежуточного слоя важен. The order of middleware is important. В предыдущем примере исключение InvalidOperationException возникает при вызове UseSession после UseMvc . In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc . Дополнительные сведения см. в разделе Порядок расположения ПО промежуточного слоя. For more information, see Middleware Ordering.

Если вы ориентируетесь на .NET Framework и используете поставщик TempData на основе сеансов, добавьте в проект пакет Microsoft.AspNetCore.Session. If targeting .NET Framework and using the session-based TempData provider, add the Microsoft.AspNetCore.Session package to the project.

Строки запроса Query strings

Вы можете передать ограниченный объем данных из одного запроса в другой, добавив их в строку запроса нового запроса. A limited amount of data can be passed from one request to another by adding it to the new request’s query string. Это удобно для захвата состояния в сохраняемом виде, что позволяет обмениваться ссылками с внедренным состоянием по электронной почте или через социальные сети. This is useful for capturing state in a persistent manner that allows links with embedded state to be shared through email or social networks. Поскольку строки запроса URL-адреса являются открытыми, никогда не используйте их для конфиденциальных данных. Because URL query strings are public, never use query strings for sensitive data.

Вдобавок к случайному раскрытию информации включение данных в строки запроса может открыть возможности для атак с подделкой межсайтовых запросов (CSRF), которые могут обманом вынудить пользователей посещать вредоносные веб-сайты во время проверки подлинности. In addition to unintended sharing, including data in query strings can create opportunities for Cross-Site Request Forgery (CSRF) attacks, which can trick users into visiting malicious sites while authenticated. Это позволит злоумышленникам похитить данные пользователей из приложения или предпринимать вредоносные действия от их имени. Attackers can then steal user data from the app or take malicious actions on behalf of the user. Любое сохраненное состояние приложения или сеанса необходимо защитить от атак CSRF. Any preserved app or session state must protect against CSRF attacks. Дополнительные сведения см. в статье Предотвращение атак с подделкой межсайтовых запросов (XSRF/CSRF). For more information, see Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks.

Скрытые поля Hidden fields

Данные можно сохранить в скрытых полях формы и опубликовать обратно при следующем запросе. Data can be saved in hidden form fields and posted back on the next request. Это типичное поведение для многостраничных форм. This is common in multi-page forms. Так как клиент может незаконно изменить данные, приложение всегда должно перепроверять данные в скрытых полях. Because the client can potentially tamper with the data, the app must always revalidate the data stored in hidden fields.

HttpContext.Items HttpContext.Items


Коллекция HttpContext.Items используется для хранения данных при обработке одного запроса. The HttpContext.Items collection is used to store data while processing a single request. Ее содержимое удаляется после обработки каждого запроса. The collection’s contents are discarded after a request is processed. Коллекцию Items часто используют для обеспечения взаимодействия компонентов или ПО промежуточного слоя, когда они выполняются в разные моменты времени во время обработки запроса и не могут передавать параметры напрямую. The Items collection is often used to allow components or middleware to communicate when they operate at different points in time during a request and have no direct way to pass parameters.

В следующем примере ПО промежуточного слоя добавляет isVerified в коллекцию Items . In the following example, middleware adds isVerified to the Items collection.

Далее в конвейере другое ПО промежуточного слоя может получить доступ к значению isVerified : Later in the pipeline, another middleware can access the value of isVerified :

Для ПО промежуточного слоя, которое используется всего одним приложением, допустимы ключи string . For middleware that’s only used by a single app, string keys are acceptable. ПО промежуточного слоя, используемое несколькими экземплярами приложения, должно использовать уникальные ключи объекта во избежание конфликтов. Middleware shared between app instances should use unique object keys to avoid key collisions. В следующем примере показано, как использовать уникальный ключ объекта, определенный в классе ПО промежуточного слоя: The following example shows how to use a unique object key defined in a middleware class:

Другой код может обратиться к значению, хранящемуся в HttpContext.Items , с помощью ключа, предоставляемого классом ПО промежуточного слоя: Other code can access the value stored in HttpContext.Items using the key exposed by the middleware class:

Данный подход также позволяет не использовать строки ключей в коде. This approach also has the advantage of eliminating the use of key strings in the code.

Кэш Cache

Кэширование — это эффективный способ хранения и извлечения данных. Caching is an efficient way to store and retrieve data. Приложение может управлять временем существования элементов кэша. The app can control the lifetime of cached items.

Кэшированные данные не связаны с конкретным запросом, пользователем или сеансом. Cached data isn’t associated with a specific request, user, or session. Будьте внимательны и не кэшируйте данные пользователя, которые можно извлечь по запросу другого пользователя. Be careful not to cache user-specific data that may be retrieved by other users’ requests.

Дополнительные сведения можно найти по адресу: Кэширование ответов в ASP.NET Core. For more information, see Кэширование ответов в ASP.NET Core.

Внедрение зависимостей Dependency Injection

Используйте внедрение зависимостей, чтобы сделать данные доступными для всех пользователей: Use Dependency Injection to make data available to all users:

Определите службу, содержащую данные. Define a service containing the data. Например, определяется класс с именем MyAppData : For example, a class named MyAppData is defined:

Добавьте класс службы в Startup.ConfigureServices : Add the service class to Startup.ConfigureServices :

Используйте класс службы данных: Consume the data service class:

Распространенные ошибки Common errors

«Unable to resolve service for type «Microsoft.Extensions.Caching.Distributed.IDistributedCache» while attempting to activate «Microsoft.AspNetCore.Session.DistributedSessionStore»» (Не удается разрешить службу для типа «Microsoft.Extensions.Caching.Distributed.IDistributedCache» при попытке активировать «Microsoft.AspNetCore.Session.DistributedSessionStore»). «Unable to resolve service for type ‘Microsoft.Extensions.Caching.Distributed.IDistributedCache’ while attempting to activate ‘Microsoft.AspNetCore.Session.DistributedSessionStore’.»

Обычно она вызвана невозможностью настройки по меньшей мере одной реализации IDistributedCache . This is usually caused by failing to configure at least one IDistributedCache implementation. Дополнительные сведения см. в разделах Распределенное кэширование в ASP.NET Core и Кэширование в памяти в ASP.NET Core. For more information, see Распределенное кэширование в ASP.NET Core and Кэширование в памяти в ASP.NET Core.

Если ПО промежуточного слоя для сеанса не удается сохранить сеанс (например, резервное хранилище недоступно), оно регистрирует исключение и запрос выполняется обычным образом. In the event that the session middleware fails to persist a session (for example, if the backing store isn’t available), the middleware logs the exception and the request continues normally. Это приводит к непредсказуемому поведению. This leads to unpredictable behavior.

Например, пользователь сохраняет корзину для покупок в сеансе. For example, a user stores a shopping cart in session. Он добавляет товар в корзину, но фиксация завершается сбоем. The user adds an item to the cart but the commit fails. Приложению неизвестно о сбое, поэтому оно сообщает пользователю, что товар добавлен в корзину, хотя это не так. The app doesn’t know about the failure so it reports to the user that the item was added to their cart, which isn’t true.

Программирование на ASP

Объект Session

Объект Session представляет собой готовое средство управления состоянием с помощью элементов cookie. Объект Session управляет временем сеанса и информацией о конечном пользователе, запрещая программисту считывать и записывать значения элементов cookie и времени проверки для сеанса. Если компьютер клиента не разрешает использование элементов cookie, то объект Session не сможет записать сеансовый элемент cookie и будет функционировать неправильно. Элемент cookie, записываемый объектом Session , не имеет срока действия, поэтому он удаляется при закрытии браузера. Объект Session содержит все данные сеанса в наборе Session.Contents . Объектом Session и набором Contents управляют так же, как и другими наборами объектов ASP. WriteCollection (особая подпрограмма в листинге 12.2) используется для отображения содержимого набора Session.Contents точно так же, как при записи элементов cookie, переменных формы и наборов QueryString в браузер. В листинге 12.5 приведен пример кода, в котором объект Session используется аналогично набору Request.Cookies .

Листинг 12.5 представляет собой код ASP, выполняющий считывание значения объекта Session , обновление значения и запись новых значений в объект Session . Подпрограмма WriteCollection представляет собой файл включения, указанный в строке . Два других свойства, уникальных для объекта Session – SessionID и Timeout – записываются в браузер. Подпрограмма UpdateSession вызывается с помощью набора Session.Contents с использованием в качестве аргументов переменных sTime и sNumber . Переменные sTime и sNumber являются пустыми переменными, которым присваиваются значения сеанса в подпрограмме. После установки значения Session.Timeout , равного 1 минуте, в браузер записывается информация об обновлениях, внесенных в сеанс.

В VBScript по умолчанию все параметры в функции или подпрограмме передаются по обращению. Это значит, что значения аргументов примут в результате работы функции или подпрограммы значения переданных аргументов. В подпрограмме UpdateSession переменным sTime и sNumber не присвоено значений при их передаче в UpdateSession в качестве аргументов. В подпрограмме значение переменной sTime устанавливается равным текущему времени с помощью функции now() , а переменной sNumber – предыдущему значению, к которому прибавляется единица. После завершения подпрограммы обе переменные sTime и sNumber содержат новые значения, присвоенные им функцией UpdateSession . Если перед любым параметром в объявлении прототипа подпрограммы расположить ключевое слово byval , то передаваемый аргумент не будет изменяться после завершения подпрограммы.

При первом выполнении кода ASP в файле ReadWriteSession.asp (см. листинг 12.5) в браузере отображаются значения объекта Session . Параметр Session.Timeout по умолчанию равен 20, и в сеансе не устанавливаются никакие значения до тех пор, пока ASP не завершит свое выполнение. На рисунке 12.10 показаны результаты первого выполнения сеансового кода ASP.

Обновление файла ReadWriteSession.asp вызывает повторное выполнение кода ASP и обновление сеансового объекта посредством присвоения новых значений, а также вывод значений в браузер (см. рис. 12.11). Объект Session может содержать значения, ассоциированные с именем, подобно элементам cookie, что позволяет использовать его в качестве механизма управления состоянием приложения между запросами страницы. Элементы cookie (см. рис. 12.9) добавлены в объект Session для демонстрации аналогии хранения и получения данных с помощью сеанса и элемента cookie. Файл ReadWriteSession.asp также устанавливает новое значение Session.Timeout , равное 1 минуте.

Ограничения объекта Session

Объект Session имеет некоторые ограничения, с которыми необходимо ознакомиться, прежде чем реализовывать управление состоянием с помощью ASP на базе объекта Session . Сеанс не повторяется и не является общим между серверами, работающими в так называемой веб-ферме.

Статистика Active Session History и представление V$SESSION

AWR snapshots (снимки) очень полезны, но Oracle по умолчанию делает их каждые 60 минут. Если вы заинтересованы в анализе проблем с производительностью, которая случилась 10 минут назад, то снимки AWR ничем не помогут. Однако все-таки способ получить эту информацию имеется. Oracle Database собирает статистику Active Session History (состоящую в основном из статистики ожидания для различных событий) для всех активных сеансов каждую секунду, и сохраняет ее в циклическом буфере в SGA. Таким образом, ASH записывает самую свежую активность сеанса (за последние пять или десять минут).

Процесс MMNL (в Oracle его называют manageability monitor light — облегченный монитор управляемости, хотя этот процесс отображается как “manageability monitor process 2”, когда запрашивается представление V$BGPROCESS) выполняет легковесные задачи управляемости, включая метрики и захват хронологической информации сеансов для средства ASH при некоторых обстоятельствах. Например, MMNL сбросит данные ASH на диск, если буфер памяти ASH заполнится до истечения часового интервала, что обычно заставляет MMON выталкивать его.
Анализ ASH предоставляет эффективные данные по производительности, поскольку сосредоточен только на активных сеансах. Анализ текущих активных сеансов выполняется с использованием представления V$ACTIVE_SESSION_HISTORY, а анализ хронологии более старых сеансов — с помощью представления DBA_HIST_ACTIVE_SESSION_HISTORY.

На заметку! Дополнительная статистика в Oracle Database не оказывает заметного влияния на производительность, поскольку поступает в основном прямо из SGA через фоновые процессы. Средство ASH использует около 2 Мбайт памяти в SGA на каждый процессор.

Данные текущего активного сеанса

Как должно быть известно, представление V$SESSION хранит данные обо всех текущих сеансах. Оно содержит 72 столбца информации, и потому слишком громоздко для анализа данных сеанса. Вот почему ASH упрощает представление V$SESSION и получает из него наиболее важную информацию ожидания. Oracle предлагает новое представление V$ACTIVE_SESSION_HISTORY, которое содержит по одной строке для каждого активного сеанса, откуда ASH делало выборку, и возвращает строку самого последнего сеанса первой.
Представление V$ACTIVE_SESSION_HISTORY — это место, где база данных хранит пример данных всех активных сеансов. В этом представлении имеется столбец по имени SESSION_STATE, который показывает, активен ли сеанс. Столбец SESSION_STATE принимает два значения: ON CPU или WAITING. Сеанс считается активным в следующих случаях:

  • состояние сеанса ON CPU, что означает активное использование сеансом процессора для выполнения работы с базой данных;
  • состояние сеанса WAITING, но столбец EVENT указывает, что сеанс не ожидает никаких событий в классе >Обратите внимание, что ASH — скользящий буфер в SGA; это находящаяся в памяти хронология активного сеанса. Таким образом, в загруженной базе данных старая информация часто перезаписывается, поскольку ASH собирает данные из представления V$SESSION каждую секунду.

На заметку! Использование статистики ASH для настройки производительности экземпляра рассматривается в главе 20.

Хронологические данные более старых сеансов

Представление словаря данных DBA_HIST_ACTIVE_SESSION_HISTORY хранит хронологическую информацию о последнем активном сеансе. Другими словами, это представление — не что иное, как коллекция снимков представления V$ACTIVE_SESSION_HISTORY, которое само по себе является образом данных активного сеанса.
Существуют два способа заполнения DBA_HIST_ACTIVE_SESSION_HISTORY.

  • В процессе получения регулярных (по умолчанию — ежечасных) снимков, выполняемых AWR, фоновый процесс MMON передает AWR данные ASH.
  • Oracle может понадобиться передать данные в представление DBA_HIST_ACTIVE_SESSION_HISTORY между моментами получения регулярных снимков, если буфер памяти окажется заполненным, и база данных не сможет записать в него данные об активности сеанса. В этом случае новый фоновый процесс MMNL выполнит выталкивание данных из буфера памяти в представление словаря данных.

Генерация отчета ASH

Для получения отчета ASH можно воспользоваться сценарием ashrpt.sql, находящимся в каталоге $ORACLE_HOME/rdbms/admin. Применение этого сценария аналогично использованию сценария awrrpt.sql, описанного ранее в этой главе. Этот сценарий генерирует информацию об операторах SQL, которые выполнялись в указанный период времени, и включает детали о блокировках и ожидании. Вот как можно запустить сценарий ashrpt.sql для получения отчета ASH:

Вам будет предложено ввести временные рамки для сбора информации ASH, кроме того, формат вывода отчета — HTML или текстовый, а также имя отчета. В листинге 1 ниже показана часть отчета ASH.

Первый раздел отчета ASH, Top User Events, предоставляет информацию о верхних пользовательских событиях, как показано в листинге 2:

Раздел Top Background Events (Верхние фоновые события), показанный в листинге 3 ниже, демонстрирует события ожидания в базе данных.

Раздел Top Service/Module (Верхняя служба/модуль), показанный в листинге 4, отображает активность, разделенную в соответствии со службами и модулями экземпляра.

В листинге 5 ниже показана информация о важнейших типах команд SQL (раздел Top SQL Command Types), выполненных в базе данных за последний час.

В листинге 6 ниже идентифицируются верхние операторы SQL (раздел Top SQL Statements), выполненные за анализируемый период ASH.

После этого следует раздел под названием Top SQL Using Literals (Верхние операторы SQL, использующие литералы), который поможет идентифицировать SQL-операторы, не использующие переменные привязки.

Следующие два сегмента, показанные в листинге 7, относятся Top Sessions (Ведущие сеансы) и Top Blocking Sessions (Ведущие блокирующие сеансы), основанные на ожиданиях в очереди и статистике ожидания занятого буфера.

Следующие три сегмента подводят итог по ведущим объектам базы данных, ведущим файлам и ведущим защелкам в экземпляре. В конце отчет ASH содержит итоговую информацию о событиях ожидания в базе данных, распределенных по меньшим временным слотам, чем общий период анализа, как показано в листинге 8.

В этом примере часовой период времени разбит на десять шестиминутных интервалов. Данный пример поможет более точно выявить моменты ухудшения производительности.

Изучение сессии в ASP.Net

Written on 04 Сентября 2013 . Posted in ASP.NET

ОГЛАВЛЕНИЕ

Данная статья описывает сессию в ASP.Net 2.0. Разные типы сессии, ее конфигурация. Также описана сессия в веб-ферме, балансировщике нагрузки, веб-саде, и т.д.

Введение

Данная статья дает хорошее понимание сессии. В ней описаны основы сессии, разные типы хранения объекта сессии, поведение сессии в веб-ферме, сессия в балансировщике нагрузки и т.д. Также объяснены особенности поведения сессии в условиях реального производства.

Что такое сессия?

Интернет не сохраняет состояние, а значит, новый экземпляр класса веб-страницы вновь создается при каждой отправке страницы на сервер. Как известно, HTTP — протокол без сохранения состояния, он не способен хранить клиентскую информацию о странице. Если пользователь вставит какие-то данные и перейдет на следующую страницу, то эти данные потеряются, и пользователь не сможет извлечь данные. Что нужно? Нужно хранить информацию. Сессия позволяет хранить информацию в памяти сервера. Она поддерживает хранение любого типа объекта наряду с пользовательским объектом. Для каждого клиента данные сессии хранятся отдельно, то есть данные сессии хранятся согласно клиенту. Посмотрите на следующую схему.

Рис. Для каждого клиента данные сессии хранятся отдельно

Управление состоянием с помощью сессии – одно из лучших средств asp.net, потому что оно безопасно, прозрачно от пользователей, и в ней можно хранить любой объект. Наряду с плюсами, порой сессия вызывает проблему быстродействия для сайтов с интенсивным трафиком, потому что сессия хранится в памяти сервера, и клиенты читают данные из самого сервера. Рассмотрим плюсы и минусы использования сессии в веб-приложении.

Плюсы и минусы сессии

Ниже приводятся основные плюсы и минусы использования сессии. Все типы сессий подробно описаны далее.

Плюсы:
• Сессия помогает хранить состояния и данные пользователя во всем приложении.
• Она легко реализуется и может хранить любой объект.
• Хранит данные каждого клиента отдельно.
• Сессия безопасна и прозрачна для пользователя.

Минусы:
• Издержки быстродействия в случае большого числа пользователей, так как данные сессии хранятся в памяти сервера.
• Издержки, связанные с сериализацией и десериализацией данных сессии, так как в случае режимов сессии StateServer и SQLServer объект надо сериализовать перед сохранением.

Кроме того, есть много плюсов и минусов сессии, обусловленных типами сессии. Все они разобраны далее.

Сохранение и извлечение значений из сессии

Сохранение и извлечение значений сессии очень похоже на ViewState. С состоянием сессии можно взаимодействовать с помощью класса System.Web.SessionState.HttpSessionState, потому что он предоставляет встроенный объект сессии со страницами Asp.Net.

Следующий код применяется для сохранения значения в сессии

Значения извлекаются из сессии так:

можно сохранить другой объект в сессии. Следующий пример показывает, как сохранить DataSet в сессии.

а следующий код показывает извлечение dataset из сессии

Идентификатор сессии

Asp.Net использует 120- битный идентификатор для отслеживания каждой сессии. Он достаточно безопасен и не подлежит расшифровке. Когда клиент общается с сервером, между ними передается только идентификатор сессии. Когда клиент запрашивает данные, ASP.NET смотрит на идентификатор сессии и извлекает соответствующие данные.

Это делается путем следующих шагов:
• Клиент обращается к веб-сайту, и какая-то информация сохраняется в сессии.
• Сервер создает уникальный идентификатор сессии для этого клиента и сохраняет его в поставщике состояния сессии.
• Снова клиент запрашивает какие-то данные с этим уникальным идентификатором сессии у сервера.
• Сервер смотрит на поставщики сессии и извлекает сериализованные данные из сервера состояний и приводит тип объекта.

Посмотрите на наглядную схему,

Рис. Взаимодействие клиента, веб-сервера и поставщика состояний


Режим сессии и поставщик состояний

В ASP.NET есть следующие режимы сессии:

• InProc
• StateServer
• SQLServer
• Custom

Для каждого состояния сессии есть поставщик сессии. Следующая схема показывает, как они связаны.

Рис. Архитектура состояния сессии

Можно выбрать поставщик состояния сессии исходя из того, какое состояние сессии выбирается. Когда ASP.NET запрашивает любую информацию на базе идентификатора сессии, состояние сессии и его соответствующий поставщик отвечают за отправку надлежащей информации на базе пользователя. Следующая таблица показывает режим сессии вместе с именем ее поставщика.

Режим состояния сессии

Поставщик состояния

Объект в памяти

Есть еще один режим «Off». Если выбрать этот вариант, сессия будет отключена для приложения. Но использование сессии является целью, поэтому рассматриваются 4 режима состояния сессии.

Состояния сессии

Состояние сессии означает все настройки, сделанные для веб-приложения для сохранения сессии. Состояние сессии сообщает все о конфигурации сессии в web.config или из выделенного кода. В web.config, элементы используются для установки конфигурации сессии. Некоторые из них — Mode, Timeout, StateConnectionString, Custom provider и др. Рассмотрены все до единой части строки подключения. Перед рассмотрением режима сессии кратко ознакомимся с событием сессии.

Событие сессии

В Asp.net есть два типа событий сессии:

оба этих события обрабатываются в файле global.asax веб-приложения. При запуске новой сессии возбуждается событие session_start, а при закрытии или окончании сессии возбуждается событие Session_End.

Режим сессии

Уже обсуждался режим сессии в ASP.NET. Ниже приводятся разные типы режимов сессии, имеющиеся в ASP.Net.
• Off
• InProc
• StateServer
• SQLServer
• Custom

Если установить режим сессии=»off» в web.config, сессия будет отключена во всем приложении. Для этого надо сконфигурировать web.config таким образом:

Внутрипроцессный режим сессии

Это режим сессии по умолчанию в Asp.Net. Он хранит данные сессии в текущем домене приложения. Это лучший режим сессии исходя из быстродействия веб-приложения. Но главный недостаток в том, что данные теряются при перезапуске сервера. Есть еще несколько плюсов и минусов внутрипроцессного режима сессии. Они рассмотрены далее.

Обзор внутрипроцессного режима сессии

Внутрипроцессный режим хранит данные сессии в текущем домене приложения. Поэтому они легко и быстро доступны.

Внутрипроцессный режим сессии хранит данные сессии в объекте памяти в домене данного приложения. Этим управляет рабочий процесс в пуле приложений. Поэтому при перезапуске сервера данные сессии теряются. Если клиент запрашивает данные, поставщик состояния считывает данные из объекта в памяти и возвращает их клиенту. В web.config надо указать режим сессии и установить время ожидания.

Такая установка времени ожидания сессии сохраняет сессию в течение 30 минут. Это можно настроить и из выделенного кода.

В asp.net есть два типа событий сессии — Session_Start() и Session_End(). Это единственный режим, поддерживающий событие Session_End(). Это событие вызывается после истечения времени ожидания сессии. Общий порядок операций для внутрипроцессного состояния сессии таков:

От времени ожидания сессии зависит, когда вызовется Session_End(). Это очень быстрый механизм, потому что при сохранении и извлечении данных не происходит сериализации, и данные остаются в том же домене приложения.

Когда следует использовать внутрипроцессный режим сессии?

Внутрипроцессный – режим сессии по умолчанию. Он очень полезен для маленьких веб-сайтов и когда число пользователей очень маленькое. Избегайте внутрипроцессного режима в случае веб-сада (эта тема подробно рассмотрена далее).

Плюсы и минусы

Плюсы:
• Данные сессии хранятся в объекте памяти текущего домена приложения. Поэтому доступ к данным очень быстрый, и данные легко доступны.
• Для хранения данных при внутрипроцессном режиме сессии не требуется сериализация.
• Реализация очень простая, сходная с использованием состояния просмотра.

Минусы:
Несмотря на то, что внутрипроцессная сессия – самый быстрый, простой и стандартный механизм, он имеет много недостатков.
• Если рабочий процесс или домен приложения возвращается в исходное состояние, все данные сессии теряются.
• Хотя он самый быстрый, но много данных сессий и много пользователей снижают быстродействие из-за памяти.
• Его нельзя использовать в веб-саде.
• Этот режим сессии не подходит для веб-фермы.

Следовательно, внутрипроцессный – очень быстрый механизм сохранения сессии, но подходящий для маленького веб-приложения. Внутрипроцессные данные сессии теряются при перезапуске сервере или возврате домена приложения в исходное состояние. Он также не подходит для веб-фермы и веб-сада.

Теперь рассмотрим другие доступные варианты для преодоления этой проблемы. Первым идет режим сервера состояний.

Режим сессии сервера состояний

Обзор режима сессии сервера состояний

Он также называется внепроцессным режимом сессии. Сервер состояний использует автономные службы Windows, не зависящие от IIS и способные работать на отдельном сервере. Этим состоянием сессии полностью управляет aspnet_state.exe. Этот сервер может работать в той же системе, но он находится вне основного домена приложения, где работает веб-приложение. При перезапуске процесса asp.net данные сессии сохраняются. Такой подход имеет несколько недостатков из-за издержек сериализации и десериализации, он также увеличивает издержки доступа к данным, так как при каждом извлечении данных сессии пользователем приложение обращается к другому процессу.

Конфигурация для режима сессии сервера состояний

В StateServer данные сессии хранятся в отдельном сервере, не зависящем от IIS и управляемом aspnet_state.exe. Этот процесс работает как службы windows. Эту службу можно запустить из консоли управления windows или из командной строки.

По умолчанию «тип запуска» службы состояний ASP.NET установлен на ручной, надо установить его как «автоматический» тип запуска

из командной строки, набрав «net start aspnet_state». По умолчанию эта служба слушает порт TCP 42424, но можно изменить порт из редактора реестра, как показывает рисунок ниже.

Теперь посмотрим на конфигурацию web.config для установки сервера состояний. Для установки сервера состояний надо задать stateConnectionString. Она будет идентифицировать систему, являющуюся работающим сервером состояний. По умолчанию stateConnectionString использует IP-адрес 127.0.0.1 (localhost) и порт 42424.

При использовании сервера состояний можно сконфигурировать атрибуты stateNetworkTimeOut, чтобы задать максимальное число секунд ожидания ответа от службы до отмены запроса. Время по умолчанию — 10 секунд.

При использовании сервера состояний объект должен сериализоваться при сохранении и десериализоваться при извлечении. Это описано в примере.

Как работает режим сессии сервера состояний?

Режим сессии сервера состояний используется для предотвращения ненужной потери данных сессии при перезапуске веб-сервера. Сервер состояний обслуживается процессом aspnet_state.exe как служба windows. Этот процесс хранит все данные сессии. Но надо сериализовать данные перед их сохранением в режиме сессии сервера состояний.

Как показано на рисунке выше, сначала клиент отправляет запрос веб-серверу, затем веб-сервер сохраняет данные сессии на сервере состояний. Сервер состояний может быть текущей системой или другой системой. Но он абсолютно независим от IIS. Адрес сервера состояний будет зависеть от установки атрибута stateConnectionString в web.config. если установить его в 127.0.0.1:42424, он будет хранить данные в самой локальной системе. Чтобы сменить адрес сервера состояний, надо сменить IP и убедиться, что aspnet_state.exe запущен и работает в той системе. Иначе выдается следующее исключение при попытке сохранить данные в сессии.

Любой объект должен быть сериализован перед сохранением в сессии. Эти данные сохраняются в системе сервера состояний с помощью поставщика состояний. При извлечении данных поставщик состояний возвращает данные. Полный порядок операций дан на рисунке ниже.

Пример режима сессии сервера состояний:

Это простой пример использования режима сессии сервера состояний. Пример веб-приложения был создан прямо на IIS, чтобы было легко понять его применение.

Шаг 1: Открыть Visual Studio > Файл(File)>Новый(New)> Веб-сайты(Web Sites). Выбрать расположение как HTTP и создать веб-приложение.

Теперь если вы откроете IIS, то увидите виртуальный каталог, созданный с именем вашего веб-приложения, в данном примере это StateServer.

Шаг 2: Создать простой пользовательский интерфейс, принимающий номер списка и имя ученика. Имя и список будут сохраняться в сессии сервера состояний. Также был создан класс «StudentInfo», приведенный ниже.

Теперь ознакомимся с кодом, отделенным от кода. Были добавлены две кнопки – одна для сохранения сессии, а вторая для извлечения сессии.

Шаг 3: Сконфигурировать web.config для сервера состояний, как уже было сказано. Убедиться, что aspnet_state.exe запущен и работает на сконфигурированном сервере.

Шаг 4: Запустить приложение

Ввести данные, нажать на Отправить. Следующий тест покажет, в чем именно польза сервера состояний.

Первый: Удалите ключевое слово [Serializable] из класса studentinfo и попробуйте запустить приложение. При нажатии на кнопку «Отправить» вы получите следующую ошибку

которая ясно говорит, что надо сериализовать объект перед сохранением.

Второй: Запустите приложение, сохраните данные, нажав на кнопку «Отправить». Перезапустите IIS

Теперь в случае InProc вы уже потеряли данные сессии, но это StateServer. Щелкните по «Восстановить сессию» и получите исходные данные, потому что данные сервера состояний не зависят от IIS. Сервер состояний хранит данные отдельно.

Третий: Остановите aspnet_state.exe из консоли управления службами Windows и отправьте данные. Вы получите следующую ошибку,

потому что процесс сервера состояний не работает. Не забывайте про три перечисленных момента.

Плюсы и минусы

Исходя из вышесказанного:

Плюсы
• Данные хранятся отдельно от IIS, поэтому проблемы с IIS не мешают данным сессии.
• Он полезен в веб-ферме и веб-саде.

Минусы
• Процесс медленный из-за сериализации и десериализации
• Сервер состояний всегда должен быть запущен и работать.

С сервером состояний закончим. Дополнительные интересные особенности есть в разделе балансировщик нагрузки, веб-ферма, веб-сад.

Режим сессии SQL Server

Обзор режима сессии SQL Server

Этот режим сессии обеспечивает более безопасное и надежное управление сессиями в asp.net. В этом режиме сессии данные сессии сериализуются и сохраняются в базе данных SQL Server. Основные недостатки данных методов хранения сессии – издержки, связанные с сериализацией и десериализацией данных. Это лучший вариант для применения в веб-фермах.

Для настройки SQL Server надо воспользоваться двумя скриптами sql.

• Для установки: InstallSqlState.sql
• Для удаления: UninstallSQLState.sql

Простейший способ сконфигурировать SQL Server – использовать команду aspnet_regsql. Использование этого файла подробно объяснено в разделе конфигурации. Это наиболее полезное управление состоянием в веб-ферме.

Когда следует использовать режим сессии SQL Server?

• Режим сессии SQL Server – более надежное и безопасное управление состоянием сессии.
• Он хранит данные в централизованном месте (база данных).
• Следует использовать режим сессии SQL server, когда нужна более безопасная реализация сессии.
• Если сервер часто перезапускается, можно реализовать SQL server.
• Этот режим прекрасно подходит для веб-фермы и веб-сада (подробно объяснено далее).
• Можно использовать режим сессии SQL server, когда сессия совместно используется двумя разными приложениями.

Конфигурация для режима сессии SQL Server

В режиме сессии SQL Server данные сессии сохраняются в SQL Server, поэтому сначала надо прописать строку подключения к базе данных в web.config.Атрибут sqlConnectionString используется для указания строки подключения в web.config.

После установки строки подключения надо сконфигурировать SQL Server. SQL server конфигурируется с помощью команды aspnet_regsql следующим образом:

Шаг 1: Из командной строки перейдите в ваш каталог версии среды разработки


Шаг 2: Выполните команду aspnet_regsql со следующими параметрами

Ознакомьтесь с параметрами и их назначениями

Параметры

Описание

Добавить поддержку режима состояния сессии SQLServer .

P означает сохраненный. Он сохраняет данные сессии на сервере.

Задать имя сервера

Задать имя пользователя

После выполнения вы получите следующее сообщение,

Шаг 3: Откройте SQL Server Management Studio. Убедитесь, что новая база данных ASPState была создана, и в ней есть две таблицы,
• ASPStateTempApplications
• ASPStateTempSessions

Теперь измените строку конфигурации примера сервера состояний и запустите то же самое приложение, что и для сервера состояний.
Сохраните список и имя пользователя и щелкните по кнопке «Отправить», и откройте таблицу ASPStateTempSessions из SQL Server Management Studio, и увидите ваши данные сессии,

Теперь проделайте следующий тест, уже описанный в режиме сервера состояний.
1. Удалите ключевое слово serialize из класса StydentInfo
2. Перезапустите IIS и щелкните по «Восстановить сессию»
3. Остановите службу SQL Server

Плюсы и минусы

Плюсы:
• Данные сессии не страдают при перезапуске IIS.
• Самое надежное и безопасное управление сессиями.
• Данные хранятся в централизованном месте, легко доступном из другого приложения.
• Очень полезен для веб-фермы и веб-сада.

Минусы:
• Обработка очень медленная по характеру.
• Сериализация и десериализация объекта создает издержки для приложения.
• Поскольку данные сессии обрабатываются в другом сервере, приходится следить за SQL server. Он всегда должен быть запущен и работать.

Пользовательский режим сессии

Обзор пользовательского режима сессии:

Обычно в приложении используется режим сессии InProc, StateServer или SQL Server, но также нужно знать основы пользовательского режима сессии. Этот режим сессии весьма интересен, потому что пользовательская сессия позволяет полностью контролировать создание всего, даже идентификатора сессии. Можно написать собственный алгоритм генерации идентификатора сессии.

Можно реализовать пользовательские поставщики, сохраняющие данные сессии в других механизмах хранения путем наследования от класса SessionStateStoreProviderBase. Можно генерировать новый идентификатор сессии путем реализации ISessionIDManager.

Следующие методы вызываются во время реализации пользовательской сессии:

В методе Initialize устанавливается пользовательский поставщик. Он будет инициализировать соединение с заданным поставщиком. SetItemExpireCallback используется для установки SessionTimeOut, можно зарегистрировать любые методы, которые вызовутся при окончании сессии. InitializeRequest вызывается при каждом запросе, а CreateNewStoreData используется для создания нового экземпляра SessionStateStoreData.

Когда следует использовать пользовательский режим сессии?

Пользовательский режим сессии можно использовать в следующих случаях:
• Надо хранить данные сессии не в SQL Server.
• Надо использовать существующую таблицу для хранения данных сессии.
• Надо создать собственный идентификатор сессии.

Какая конфигурация требуется для него?

Надо сконфигурировать web.config так,

Плюсы и минусы

Плюсы:
• Можно использовать существующую таблицу для хранения данных сессии. Это полезно, когда приходится использовать старую базу данных вместо SQL Server.
• Он не зависит от IIS, поэтому перезапуск веб-сервера никак не влияет на данные сессии.
• Можно создать собственный алгоритм генерации идентификатора сессии.

Минусы:
• Обработка данных очень медленная.
• Создание пользовательского поставщика состояния – низкоуровневая задача, требующая аккуратного подхода для обеспечения безопасности.

Всегда рекомендуется использовать любой сторонний поставщик, а не создавать собственный.

Обзор производственного развертывания

Производственная среда означает, что приложение развертывается на настоящем рабочем сервере. Развертывание приложения на настоящем сервере – большая трудность для веб-разработчика, потому что в масштабной производственной среде много пользователей, и невозможно справиться с нагрузкой от них с помощью одного сервера. Отсюда появились модели веб-фермы, балансировщика нагрузки, веб-сада, и т.д.
Недавно одно веб-приложение было развернуто в реальной производственной среде, доступной для миллиона пользователей, где было более 10 Active Directory, более 10 веб-серверов на балансировщике нагрузки и много серверов баз данных, серверов Exchange Server, серверов LCS и др. Было несколько веб-серверов. Основной риск, связанный с несколькими серверами, — управление сессиями. Следующий рисунок показывает общую схему производственной среды.

Далее описаны разные ситуации, которые надо учесть при развертывании приложения.

Пул приложений

Это одна из самых важных вещей, которую надо создать для приложения в производственной среде. Пулы приложений применяются для отделения групп рабочих процессов IIS, совместно использующих одну и ту же конфигурацию. Пул приложений позволяет изолировать веб-приложение для лучшей безопасности, надежности и доступности. Рабочий процесс служит в качестве границы процессов, отделяющей каждый пул приложений, чтобы когда один рабочий процесс или приложение сталкивается с проблемой или возвращается в исходное состояние, другие приложения или рабочие процессы не страдали.

Удостоверение пула приложений

Конфигурация удостоверения пула приложений – важный аспект безопасности в IIS 6.0 и IIS 7.0, так как она определяет удостоверение рабочего процесса, когда процесс обращается к ресурсу. Эти настройки исходят из IIS 6.0. В IIS 7.0 есть заранее заданные удостоверения, такие же, как и в IIS 6.0.

Удостоверение пула приложений

Описание

LocalSystem – встроенная учетная запись, имеющая права администратора на сервере. Она может обращаться к локальным и удаленным ресурсам. Для любого вида доступа к файлам или ресурсам сервера надо задать удостоверение пула приложений Локальная система.

LocalServices – встроенная учетная запись имеет права аутентифицированной учетной записи локального пользователя. Ей запрещен доступ к сети.

Удостоверение пула приложений по умолчанию. NetworkServices имеет права аутентифицированной учетной записи локального пользователя.

Создание и назначение пула приложений

Откройте консоль IIS, щелкните правой кнопкой мыши по «Папка пула приложений» (Application Pool Folder) > Создать новый (Create New)

Введите Идентификатор пула приложений и нажмите Ok.

Теперь щелкните правой кнопкой мыши по «Виртуальный каталог» (используется StateServer Web sites) и назначьте StateServerAppPool виртуальному каталогу сервера состояний.

Итак, StateServer Web sites будет работать независимо в StateServerAppPool. Любая проблема, связанная с другим приложением, не повлияет на ваше приложение. Это главное преимущество создания отдельного пула приложений.

Веб-сад

По умолчанию каждый пул приложений работает с одним рабочим процессом (W3Wp.exe). Можно назначить несколько рабочих процессов одному пулу приложений. Пул приложений с несколькими рабочими процессами называется веб-сад. Много рабочих процессов в одном и том же пуле приложений иногда дают лучшую производительность и время реакции приложения. Каждый рабочий процесс должен иметь свой собственный поток и область памяти.

Как показано на рисунке, в сервере IIS может быть несколько пулов приложений, и каждый пул приложений имеет минимум один рабочий процесс. Веб-сад должен содержать несколько рабочих процессов.

Есть определенные ограничения на использование веб-сада в веб-приложении. Если используется внутрипроцессный режим сессии, приложение не будет работать правильно, потому что сессия будет обрабатываться другим рабочим процессом. Во избежание данной проблемы надо использовать внепроцессный режим сессии. Можно использовать «Сервер состояния сессии» или «Состояние сессии SQL-Server».

Главное преимущество: Рабочие процессы в веб-саде разделяют запросы, поступающие в конкретный пул приложений. Если один рабочий процесс откажет, другой рабочий процесс сможет продолжить обработку запросов.

Как создать веб-сад?

Щелкните правой кнопкой мыши по Пул приложений > Перейти во вкладку Производительность > Выбрать секцию веб-сад (выделена на рисунке)

По умолчанию стоит 1, измените на несколько.

Как сессия зависит от веб-сада?

InProc управляется рабочим процессом. Он хранит данные внутри своего объекта памяти. Если есть несколько рабочих процессов, то обрабатывать сессию будет очень трудно, потому что каждый рабочий процесс имеет свою собственную память. Поэтому если первый запрос пользователя уходит к WP1, и он хранит его данные сессии, и второй запрос того же пользователя уходит к WP2, и пользователь пытается извлечь данные сессии, они не вернутся, и выбросится ошибка. Поэтому не используйте веб-сад во внутрипроцессном режиме сессии.

В случае веб-сада можно использовать режим сессии StateServer или SQLServer, потому что эти два режима сессии не зависят от рабочего процесса. В примере показано, что после перезапуска IIS данные сессии успешно извлекаются.

Сессии в ASP.NET или как создать собственный провайдер

ASP.NET предлагает множество вариантов для работы с сессиями из коробки:

  • Хранение информации о сессиях в памяти сервера, внутри процесса ASP.NET
  • Хранение информации о сессиях на сервере состояний
  • Хранение информации о сессиях в базе данных SQL Server в заранее предопределенной схеме

Но сколько бы ни было вариантов из коробки, они не могут полностью ответить на те задачи, которые встают перед разработчиком. В этой статье мы рассмотрим как реализовать собственный провайдер хранилища состояния сессий (сеансов) для ASP.NET (MVC).

В качестве хранилища сессий будет выступать SQL Server. Работать с базой данных мы будем через EntityFramework.

Оглавление

Почему я пишу эту статью?

Продолжительное время я занимался разработкой сайтов на php. В какой-то момент я решил освоить что-то новое и выбрал для этого ASP.NET. Через призму php сессии, авторизация, membership и роли в ASP.NET вызывали у меня множество вопросов и неудовлетворенность от непонимания того как это работает, а то что было понятно, вызывало раздражение, потому что это работало недостаточно хорошо.

Теперь, несколько лет спустя, я решил создать цикл статей не просто для того, чтобы объяснить как это работает, а для того, чтобы показать, что в ASP.NET нет ничего того, что нельзя было бы изменить и сделать по своему.

Причины реализации собственного провайдера

Использование не поддерживаемого хранилища

Продукты от Microsoft стоят достаточно дорого и это факт, а бесплатные версии имеют ряд ограничений. Таким образом, вы можете захотеть использовать другую базу данных в бесплатной редакции, например MySQL или PostgreSQL.

С другой стороны, вы можете захотеть использовать Key-Value хранилище, чтобы повысить производительность распределенного приложения. Или может быть у вас просто у вас есть уже купленные лицензии на продукты других компаний.

Нестандартная схема таблиц базы данных

Эта причина является наиболее частой.

Стандартные возможности — это хорошо, но чем более сложным становится приложение, тем более нестандартных решений оно требует для своей работы.

Пример:
На сайте требуется, сделать возможность закрывать сессии (делать принудительных выход — logout) для конкретных пользователей. Стандартная схема базы данных для SQL Server не поддерживает этой функциональности, так как в сессиях не хранится информация о принадлежности к пользователям.

Кем и как управляются сессии в ASP.NET

За обработку состояния (сессий) отвечает SessionStateModule, он является обработчиком по умолчанию. При желании можно реализовать собственный http-модуль, отвечающий за обработку сессий.

Объект SessionStateModule взаимодействует с провайдером сессий, вызывая определенные методы провайдера в течении своей работы. Какой провайдер сессий использовать модуль определяет на основе конфигурации веб приложения. Любой провайдер сессий должен наследоваться от класса SessionStateStoreProviderBase, который и определяет необходимые для SessionStateModule методы.

Схема работы сессий

Ниже представлена краткая схеме вызова методов провайдера, для того, чтобы лучше понять, как работают сессии в ASP.NET (кликабельна).

Рис. Последовательность вызова методов для работы с сессиями


Сначала SessionStateModule определяем режим работы с сессией для данной страницы (ASP.NET WebForms) или контроллера (ASP.NET MVC).

Если для страницы установлен атрибут:

(или атрибут SessionState для для ASP.NET MVC)

То работа с сессией будет происходить в режиме Read Only (только для чтения), что несколько повышает общую производительность. В противном случае модуль SessionStateModule запрашивает эксклюзивный доступ и блокирует содержимое сессии. Блокировка снимается только в завершающей стадии выполнения запроса.

Зачем нужны блокировки сессий?

Приложения ASP.NET — это многопотоковые приложения, а ajax технологии очень популярны. Может сложится ситуация, что к сессии одного и того же пользователя обратится сразу несколько потоков, для того, чтобы избежать конфликтов, перезаписи сохраненных значений или извлечения устаревших значений, используются блокировки.

Блокировки происходят только при обращении к сессии одного и того же пользователя со стороны нескольких потоков.

Тот поток, который обратился к ресурсам сессий первый получает эксклюзивный доступ на время выполнения запроса. Остальные потоки ожидают до тех пор, пока ресурсы не освободятся, либо до тех пор пока не выйдет небольшой таймаут.

Мы можем реализовать провайдер без поддержки блокировки, если у нас есть причины полагать, что конфликтов между потоками не будет, либо они не приведут к значимым последствиям.

Реализация провайдера сессий

Создание таблицы для хранения данных сессии

Я буду использовать следующую структуру таблицы для хранения данных о состоянии сессий:

Она поддерживает блокировки. Так же я добавил поле UserId, для своих нужд, чтобы хранить информацию о пользователе, которому принадлежит сессия (например, чтобы сделать принудительный logout пользователя из панели администратора).

SessionId Уникальная строковая метка, генерируется не нами. Это случайное число, закодированное в строку, сотоящую из букв латинского алфавита и цифр, достигает в длину максимум 24 символа.
Created Время создание сессии.
Expires Время, когда истекает сессия.
LookDate Момент когда была заблокирована сессия.
LookId Номер блокировки сессии.
Looked Есть ли в данным момент блокировка.
ItemContent Содержимое сессии в сериализованном виде.
UserId >

SQL запрос на создание описанной выше таблицы (SQL Server):

Создание модели данных EntityFramework

Я хочу избавить себя от написания SQL запросов вручную и сэкономить время, поэтому я буду использовать ADO.NET EntityFramework. При этом я потеряю немного в производительности кода, по сравнению с ручным созданием SQL запросов.

Для этого я воспользуюсь мастером ADO.NET Entity Data Model, чтобы создать нужную мне модель.

Рис. Выбор мастера ADO.NET Entity Data Model для создания модели данных

Я назвал созданную сущность DbSession. После чего я воспользуюсь шаблонами генерации кода для того, чтобы создать необходимый для работы класс и контекст для взаимодействия с базой данных. Контекст управляет коллекцией сущностей из базы данных.

Рис. Выбор меню для применения шаблонов генерации кода

Мне по душе DbContext API, который доступен начиная с 4.1 версии EntityFramework, именно его я и выберу.

Рис. Выбор DbContext в качестве шаблона генерации кода

Готово, теперь у меня есть контекст с именем CommonEntities и класс DbSession. Можно приступать к реализации провайдера.

Реализация провайдера

Для начала нам необходимо создать класс, который будет наследоваться от базового класса SessionStateStoreProviderBase.

Далее необходимо реализовать ряд методов, о которых лучше расскажет документация или нижеприведенный код с комментариями:

Настройка конфигурации

После того как мы реализовали провайдер, необходимо его зарегистрировать в конфигурации. Для этого нужно добавить нижеприведенный код в раздел :

При этом CustomSessionStateProvider.Infrastructure.SessionProvider.SessionStateProvider — это полное название класса нашего провайдера, включая пространство имен. У вас оно будет скорее всего свое.

Тестирование провайдера

Для того, чтобы продемонстрировать работу сессий я создал пустое ASP.NET MVC 3 приложение, где создал контроллер HomeController и определил ряд actions, которые отображают и записывают в сессию различные элементы, в том числе список и объект пользовательского класса.

Содержимое представлений (View) я приводить не буду, в конце статьи находится ссылка на исходные коды. Вместо этого я приведу результат, который я получил в браузере, последовательно вызывая действия контроллера.

Заключение

В заключение я лишь хочу добавить, что не нужно боятся отходить от стандартов, часто собственные решения позволяют создавать более производительные и гибкие приложения.

Использование объекта Session в ASP.NET

Мне недавно была задана новая задача для загрузки сайта, созданного кем-то другим. Но я абсолютно не знаком с Интернетом. Веб-сайт находится в ASP.NET, С#. Сам код не трудно понять, кроме объекта Session. Я не понимаю, где, как и почему он использовался. Может ли кто-нибудь объяснить использование объекта Session с возможным примером?

P.S. Что означают эти две строки?

Session используется для хранения данных для пользовательского сеанса на веб-сайте. (это хранилище данных является сеансом пользовательского браузера и может подвергаться стиранию в любое время различными событиями приложения).

Обычно он используется для хранения информации по нескольким просмотрам страниц в пользовательском сеансе (то есть посещении) на вашем веб-сайте.

Его можно использовать в любом месте кода, который выполняется в контексте пользовательского сеанса; значение внутри страницы или в соответствующих жизненных циклах приложения, которые выполняются в контексте сеанса (например, запуск сеанса)

Что касается ваших образцов,

Первый, я не могу полностью объяснить, поскольку я не знаю, что должна делать функция sh.pensDec() .

Второй проверяет, есть ли значение, хранящееся в этой переменной сеанса, перед запуском следующего кода.

HTTP по своей природе является апатридом. WebServer не знает никаких подробностей после того, как он обработает запрос и отправит его клиенту. Таким образом, любые последующие запросы похожи на свежие запросы на сервер.

Чтобы включить сервер для запоминания и последующего распознавания того, что он обслуживал для клиента, ASP.NET использует различные механизмы, из которых Session является одним из них.

Сессия создается для каждого пользователя. Итак, на вашей странице вы загружаете «connSTR», сохраняете ее. Всякий раз, когда последующий запрос поступает от одного и того же пользователя, путем запроса сеанса с ключом

вы вернете его значение. Поскольку Session является объектом, его отличает строка в коде.

Состояние сеанса и приложения в ASP.NET Core Session and app state in ASP.NET Core

HTTP — это протокол без отслеживания состояния. HTTP is a stateless protocol. Без дополнительных действий HTTP-запросы являются независимыми сообщениями, которые не сохраняют значения пользователя или состояние приложения. Without taking additional steps, HTTP requests are independent messages that don’t retain user values or app state. В этой статье описывается несколько подходов для сохранения данных пользователя и состояния приложения между запросами. This article describes several approaches to preserve user data and app state between requests.

Управление состоянием State management

Состояние можно сохранить несколькими способами. State can be stored using several approaches. Эти способы обсуждается ниже в данном разделе. Each approach is described later in this topic.

Способ хранения данных Storage approach Механизм хранения Storage mechanism
Файлы «cookie» Cookies Файлы cookie HTTP (могут содержать данные, сохраненные с помощью кода приложения на стороне сервера) HTTP cookies (may include data stored using server-side app code)
Состояние сеанса Session state Файлы cookie HTTP и код приложения на стороне сервера HTTP cookies and server-side app code
TempData TempData Файлы cookie HTTP или состояние сеанса HTTP cookies or session state
Строки запросов Query strings Строки запросов HTTP HTTP query strings
Скрытые поля Hidden fields Поля формы HTTP HTTP form fields
HttpContext.Items HttpContext.Items Код приложения на стороне сервера Server-side app code
Кэш Cache Код приложения на стороне сервера Server-side app code
Введение зависимостей Dependency Injection Код приложения на стороне сервера Server-side app code

Файлы cookie хранят данные между запросами. Cookies store data across requests. Так как файлы cookie отправляются с каждым запросом, их размер нужно свести к минимуму. Because cookies are sent with every request, their size should be kept to a minimum. В идеальном случае файл cookie должен содержать лишь идентификатор, а сами данные хранятся в приложении. Ideally, only an identifier should be stored in a cookie with the data stored by the app. Большинство браузеров позволяют использовать файлы cookie размером до 4096 байт. Most browsers restrict cookie size to 4096 bytes. Для каждого домена доступно лишь ограниченное число файлов cookie. Only a limited number of cookies are available for each domain.

Так как файлы cookie могут быть незаконно изменены, их нужно проверять в приложении. Because cookies are subject to tampering, they must be validated by the app. Файлы cookie могут удаляться пользователем и имеют ограниченный срок хранения на клиентах. Cookies can be deleted by users and expire on clients. Тем не менее файлы cookie обычно являются самым надежным способом хранения данных на стороне клиента. However, cookies are generally the most durable form of data persistence on the client.

Файлы cookie часто используются для персонализации, когда содержимое настраивается под известного пользователя. Cookies are often used for personalization, where content is customized for a known user. В большинстве случаев пользователь проходит только идентификацию, а не проверку подлинности. The user is only identified and not authenticated in most cases. Файл cookie может хранить имя пользователя, имя учетной записи или уникальный идентификатор пользователя (например, GUID). The cookie can store the user’s name, account name, or unique user ID (such as a GUID). Затем можно использовать файл cookie для доступа к личным настройкам пользователя, таким как цвет фона на веб-сайте. You can then use the cookie to access the user’s personalized settings, such as their preferred website background color.

Помните об Общем регламенте по защите данных в ЕС (GDPR) при создании файлов cookie и решении вопросов с конфиденциальностью. Be mindful of the European Union General Data Protection Regulations (GDPR) when issuing cookies and dealing with privacy concerns. Дополнительные сведения см. в разделе Общий регламент по защите данных (GDPR), принятый в ЕС, в ASP.NET Core. For more information, see General Data Protection Regulation (GDPR) support in ASP.NET Core.

Состояние сеанса Session state

Состояние сеанса — это сценарий ASP.NET Core для хранения пользовательских данных, когда пользователь находится в веб-приложении. Session state is an ASP.NET Core scenario for storage of user data while the user browses a web app. Состояние сеанса использует хранилище, обслуживаемое приложением, для сохранения данных между запросами от клиента. Session state uses a store maintained by the app to persist data across requests from a client. Данные сеанса поддерживаются кэшем и считаются временными, — сайт должен работать и без данных сеанса. The session data is backed by a cache and considered ephemeral data—the site should continue to function without the session data. Критически важные данные приложения должны храниться в пользовательской базе данных и кэшироваться в сеансе только в качестве оптимизации производительности. Critical application data should be stored in the user database and cached in session only as a performance optimization.

Сеанс не поддерживается в приложениях SignalR, так как хаб SignalR может выполняться независимо от контекста HTTP. Session isn’t supported in SignalR apps because a SignalR Hub may execute independent of an HTTP context. Например, это может произойти, если хаб поддерживает длительный запрос на опрос открытым, когда время существования контекста HTTP для запроса уже истекло. For example, this can occur when a long polling request is held open by a hub beyond the lifetime of the request’s HTTP context.

ASP.NET Core сохраняет состояние сеанса, предоставляя клиенту файл cookie, содержащий идентификатор сеанса, который отправляется в приложение вместе с каждым запросом. ASP.NET Core maintains session state by providing a cookie to the client that contains a session ID, which is sent to the app with each request. Приложение использует этот идентификатор для получения данных сеанса. The app uses the session ID to fetch the session data.

Состояние сеанса реагирует на события следующим образом: Session state exhibits the following behaviors:

  • Так как файл cookie сеанса относится к конкретному браузеру, обеспечить общий доступ к сеансам из разных браузеров невозможно. Because the session cookie is specific to the browser, sessions aren’t shared across browsers.
  • Файлы cookie сеанса удаляются при завершении сеанса браузера. Session cookies are deleted when the browser session ends.
  • Если получен файл cookie для просроченного сеанса, создается сеанс, использующий этот же файл. If a cookie is received for an expired session, a new session is created that uses the same session cookie.
  • Пустые сеансы не сохраняются — в сеансе должно быть хотя бы одно значение, чтобы его можно быть сохранить между запросами. Empty sessions aren’t retained—the session must have at least one value set into it to persist the session across requests. Если сеанс не сохраняется, для каждого нового запроса создается новый идентификатор сеанса. When a session isn’t retained, a new session ID is generated for each new request.
  • Приложение хранит сеанс некоторое время после последнего запроса. The app retains a session for a limited time after the last request. Приложение устанавливает время ожидания сеанса или использует значение по умолчанию, равное 20 минутам. The app either sets the session timeout or uses the default value of 20 minutes. Состояние сеанса оптимально подходит для сохранения пользовательских данных, относящихся к определенному сеансу, которые не требуется хранить бессрочно для нескольких сеансов. Session state is ideal for storing user data that’s specific to a particular session but where the data doesn’t require permanent storage across sessions.
  • Данные сеанса удаляются при вызове реализации ISession.Clear или когда истекает срок действия сеанса. Session data is deleted either when the ISession.Clear implementation is called or when the session expires.
  • Не существует механизма по умолчанию, который бы информировал код приложения о том, что браузер клиента закрыт или файл cookie сеанса удален или просрочен на клиенте. There’s no default mechanism to inform app code that a client browser has been closed or when the session cookie is deleted or expired on the client.
  • Шаблоны ASP.NET Core MVC и Razor Pages поддерживают общий регламент по защите данных (GDPR). The ASP.NET Core MVC and Razor pages templates include support for General Data Protection Regulation (GDPR). Файлы cookie для состояния сеанса не помечаются как основные по умолчанию, поэтому состояние сеанса недоступно, если отслеживание разрешено посетителем сайта. Session state cookies aren’t marked essential by default, so session state isn’t functional unless tracking is permitted by the site visitor. Дополнительные сведения можно найти по адресу: Поддержка Общий регламент по защите данных (GDPR) в ASP.NET Core. For more information, see Поддержка Общий регламент по защите данных (GDPR) в ASP.NET Core.

Не храните конфиденциальные данные в состоянии сеанса. Don’t store sensitive data in session state. Пользователь может не закрывать браузер и очистить файл cookie сеанса. The user might not close the browser and clear the session cookie. Некоторые браузеры сохраняют файлы cookie сеанса в нескольких окнах браузера. Some browsers maintain valid session cookies across browser windows. Сеанс может быть не ограничен одним пользователем — следующий пользователь продолжит использовать приложение с тем же файлом cookie сеанса. A session might not be restricted to a single user—the next user might continue to browse the app with the same session cookie.

Поставщик кэша в памяти хранит данные сеанса в памяти сервера, содержащего приложение. The in-memory cache provider stores session data in the memory of the server where the app resides. В сценарии с фермой серверов: In a server farm scenario:

  • Используйте прикрепленные сеансы для привязки сеанса к конкретному экземпляру приложения на отдельном сервере. Use sticky sessions to tie each session to a specific app instance on an individual server. Служба приложений Azure использует маршрутизацию запросов приложений (ARR), чтобы прикрепленные сеансы создавались по умолчанию. Azure App Service uses Application Request Routing (ARR) to enforce sticky sessions by default. Однако прикрепленные сеансы могут негативно повлиять на масштабируемость и усложнить обновление веб-приложений. However, sticky sessions can affect scalability and complicate web app updates. Лучше использовать распределенные кэши SQL Server или Redis, для которых прикрепленные сеансы не требуются. A better approach is to use a Redis or SQL Server distributed cache, which doesn’t require sticky sessions. Дополнительные сведения можно найти по адресу: Распределенное кэширование в ASP.NET Core. For more information, see Распределенное кэширование в ASP.NET Core.
  • Файл cookie сеанса шифруется через IDataProtector. The session cookie is encrypted via IDataProtector. Необходимо правильно настроить защиту данных, чтобы читать файлы cookie сеанса на каждом компьютере. Data Protection must be properly configured to read session cookies on each machine. Дополнительные сведения см. статьях Защита данных в ASP.NET Core и Key storage providers in ASP.NET Core (Поставщики хранилища ключей в ASP.NET Core). For more information, see Защита данных в ASP.NET Core and Key storage providers.

Настройка состояния сеанса Configure session state

Пакет Microsoft.AspNetCore.Session, который входит в метапакет Microsoft.AspNetCore.App, предоставляет ПО промежуточного слоя для управления состоянием сеанса. The Microsoft.AspNetCore.Session package, which is included in the Microsoft.AspNetCore.App metapackage, provides middleware for managing session state. Чтобы включить сеанс ПО промежуточного слоя для сеансов, Startup должен содержать: To enable the session middleware, Startup must contain:

  • Любой из кэшей памяти IDistributedCache, Any of the IDistributedCache memory caches. при этом реализация IDistributedCache используется в качестве резервного хранилища для сеанса. The IDistributedCache implementation is used as a backing store for session. Дополнительные сведения можно найти по адресу: Распределенное кэширование в ASP.NET Core. For more information, see Распределенное кэширование в ASP.NET Core.
  • Вызов AddSession в ConfigureServices . A call to AddSession in ConfigureServices .
  • Вызов UseSession в Configure . A call to UseSession in Configure .

Следующий код показывает, как настроить поставщик сеансов в памяти с реализацией в памяти IDistributedCache по умолчанию: The following code shows how to set up the in-memory session provider with a default in-memory implementation of IDistributedCache :

Порядок ПО промежуточного слоя важен. The order of middleware is important. В предыдущем примере исключение InvalidOperationException возникает при вызове UseSession после UseMvc . In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc . Дополнительные сведения см. в разделе Порядок расположения ПО промежуточного слоя. For more information, see Middleware Ordering.

После настройки состояния сеанса доступно свойство HttpContext.Session. HttpContext.Session is available after session state is configured.

Невозможно получить доступ к HttpContext.Session до вызова UseSession . HttpContext.Session can’t be accessed before UseSession has been called.

Невозможно создать новый сеанс с новым файлом cookie сеанса после того, как приложение начинает запись в поток ответа. A new session with a new session cookie can’t be created after the app has begun writing to the response stream. Исключение записывается в журнал веб-сервера и не отображается в браузере. The exception is recorded in the web server log and not displayed in the browser.

Асинхронная загрузка состояния сеанса Load session state asynchronously

Поставщик сеансов по умолчанию в ASP.NET Core загружает запись сеанса из резервного хранилища IDistributedCache в асинхронном режиме только при явном вызове метода ISession.LoadAsync перед методами TryGetValue, Set или Remove. The default session provider in ASP.NET Core loads session records from the underlying IDistributedCache backing store asynchronously only if the ISession.LoadAsync method is explicitly called before the TryGetValue, Set, or Remove methods. Если LoadAsync не вызывается первым, базовая запись сеанса загружается синхронно, что может негативно повлиять на производительность. If LoadAsync isn’t called first, the underlying session record is loaded synchronously, which can incur a performance penalty at scale.


Чтобы принудительно использовать этот режим в приложениях, используйте для реализаций DistributedSessionStore и DistributedSession оболочку из версий, которые выдают исключение, когда метод LoadAsync не вызывается перед TryGetValue , Set или Remove . To have apps enforce this pattern, wrap the DistributedSessionStore and DistributedSession implementations with versions that throw an exception if the LoadAsync method isn’t called before TryGetValue , Set , or Remove . Зарегистрируйте версии оболочки в контейнере служб. Register the wrapped versions in the services container.

Параметры сеанса Session options

Чтобы переопределить значения по умолчанию для сеанса, используйте SessionOptions. To override session defaults, use SessionOptions.

Параметр Option ОПИСАНИЕ Description
Файл cookie Cookie Определяет параметры, используемые для создания файлов cookie. Determines the settings used to create the cookie. Параметр Name по умолчанию имеет значение SessionDefaults.CookieName ( .AspNetCore.Session ). Name defaults to SessionDefaults.CookieName ( .AspNetCore.Session ). Параметр Path по умолчанию имеет значение SessionDefaults.CookiePath ( / ). Path defaults to SessionDefaults.CookiePath ( / ). Параметр SameSite по умолчанию имеет значение SameSiteMode.Lax ( 1 ). SameSite defaults to SameSiteMode.Lax ( 1 ). Параметр HttpOnly по умолчанию имеет значение true . HttpOnly defaults to true . Параметр IsEssential по умолчанию имеет значение false . IsEssential defaults to false .
IdleTimeout IdleTimeout IdleTimeout указывает, как долго сеанс может быть неактивным, прежде чем его содержимое отбрасывается. The IdleTimeout indicates how long the session can be idle before its contents are abandoned. Каждый доступ к сеансу сбрасывает время ожидания. Each session access resets the timeout. Этот параметр применяется только к содержимому сеанса, а не к файлу cookie. This setting only applies to the content of the session, not the cookie. Значение по умолчанию — 20 минут. The default is 20 minutes.
IOTimeout IOTimeout Максимальный период загрузки сеанса из хранилища или его сохранения обратно в хранилище. The maximum amount of time allowed to load a session from the store or to commit it back to the store. Этот параметр может применяться только к асинхронным операциям. This setting may only apply to asynchronous operations. Время ожидания можно отключить с помощью InfiniteTimeSpan. This timeout can be disabled using InfiniteTimeSpan. Значение по умолчанию — 1 минута. The default is 1 minute.

Сеанс использует файл cookie для отслеживания и идентификации запросов в одном браузере. Session uses a cookie to track and identify requests from a single browser. По умолчанию этот файл cookie называется .AspNetCore.Session и использует путь / . By default, this cookie is named .AspNetCore.Session , and it uses a path of / . Так как по умолчанию файл cookie не указывает домен, он остается недоступным для клиентского сценария на странице (так как HttpOnly по умолчанию имеет значение true ). Because the cookie default doesn’t specify a domain, it isn’t made available to the client-side script on the page (because HttpOnly defaults to true ).

Чтобы переопределить файл cookie по умолчанию для сеанса, используйте SessionOptions : To override cookie session defaults, use SessionOptions :

Приложение использует свойство IdleTimeout, чтобы определить, как долго сеанс может оставаться неактивным до сброса его содержимого в кэше сервера. The app uses the IdleTimeout property to determine how long a session can be idle before its contents in the server’s cache are abandoned. Это свойство не зависит от срока действия файла cookie. This property is independent of the cookie expiration. Каждый запрос, проходящий через ПО промежуточного слоя сеанса, сбрасывает это время ожидания. Each request that passes through the Session Middleware resets the timeout.

Состояние сеанса является неблокирующим. Session state is non-locking. Когда два запроса пытаются изменить содержимое сеанса, последний из них переопределяет первый. If two requests simultaneously attempt to modify the contents of a session, the last request overrides the first. Session реализован в виде согласованного сеанса, что означает, что все содержимое хранится вместе. Session is implemented as a coherent session, which means that all the contents are stored together. Когда два запроса пытаются изменить разные значения сеанса, последний запрос может переопределить изменения, внесенные первым. When two requests seek to modify different session values, the last request may override session changes made by the first.

Установка и получение значений сеанса Set and get Session values

Получить доступ к состоянию сеанса можно через класс Razor Pages PageModel или класс MVC Controller со свойством HttpContext.Session. Session state is accessed from a Razor Pages PageModel class or MVC Controller class with HttpContext.Session. Оно является реализацией ISession. This property is an ISession implementation.

Реализация ISession предоставляет несколько методов расширения для задания и извлечения значений типа integer и string. The ISession implementation provides several extension methods to set and retrieve integer and string values. Методы расширения находятся в пространстве имен Microsoft.AspNetCore.Http (добавьте оператор using Microsoft.AspNetCore.Http; , чтобы получить доступ к методам расширения), когда проект ссылается на пакет Microsoft.AspNetCore.Http.Extensions. The extension methods are in the Microsoft.AspNetCore.Http namespace (add a using Microsoft.AspNetCore.Http; statement to gain access to the extension methods) when the Microsoft.AspNetCore.Http.Extensions package is referenced by the project. Оба пакета входят в метапакет Microsoft.AspNetCore.App. Both packages are included in the Microsoft.AspNetCore.App metapackage.

Методы расширения ISession : ISession extension methods:

В следующем примере извлекается значение сеанса для ключа IndexModel.SessionKeyName ( _Name в примере приложения) на странице Razor Pages: The following example retrieves the session value for the IndexModel.SessionKeyName key ( _Name in the sample app) in a Razor Pages page:

В следующем примере показано, как задать, а затем получить значения integer и string: The following example shows how to set and get an integer and a string:

Все данные сеанса должны быть сериализованы, чтобы использовать сценарий-распределенного кэша даже при использовании кэша в памяти. All session data must be serialized to enable a distributed cache scenario, even when using the in-memory cache. Предоставляются минимальные сериализаторы строки и числа (см. методы и методы расширения ISession). Minimal string and number serializers are provided (see the methods and extension methods of ISession). Сложные типы должны быть сериализованы пользователем с помощью другого механизма, например JSON. Complex types must be serialized by the user using another mechanism, such as JSON.

Добавьте приведенные ниже методы расширения, чтобы задавать и получать сериализуемые объекты: Add the following extension methods to set and get serializable objects:

Следующий пример показывает, как задать и получить сериализуемый объект с помощью методов расширения: The following example shows how to set and get a serializable object with the extension methods:

TempData TempData

ASP.NET Core предоставляет TempData Razor Pages или TempData контроллера. ASP.NET Core exposes the Razor Pages TempData or Controller TempData. Это свойство хранит данные до тех пор, пока они не будут прочитаны в другом запросе. This property stores data until it’s read in another request. Для проверки данных без удаления можно использовать методы Keep(String) и Peek(String) в конце запроса. Keep(String) and Peek(string) methods can be used to examine the data without deletion at the end of the request. Keep() помечает все элементы в словаре для хранения. Keep() marks all items in the dictionary for retention. TempData особенно удобно использовать для перенаправления, когда данные требуются для нескольких запросов. TempData is particularly useful for redirection when data is required for more than a single request. TempData реализуется поставщиками TempData , например, с помощью файлов cookie или состояния сеанса. TempData is implemented by TempData providers using either cookies or session state.

Примеры TempData TempData samples

Рассмотрим следующую страницу, которая создает клиент: Consider the following page that creates a customer:

На следующей странице отображается TempData[«Message»] : The following page displays TempData[«Message»] :

В предыдущей разметке в конце запроса TempData[«Message»] не удаляется, так как используется Peek . In the preceding markup, at the end of the request, TempData[«Message»] is not deleted because Peek is used. На обновляемой странице отображается TempData[«Message»] . Refreshing the page displays TempData[«Message»] .

Следующая разметка похожа на приведенный выше код, но в ней используется Keep для сохранения данных в конце запроса: The following markup is similar to the preceding code, but uses Keep to preserve the data at the end of the request:

При переходе между страницами IndexPeek и IndexKeep TempData[«Message»] не удаляется. Navigating between the IndexPeek and IndexKeep pages won’t delete TempData[«Message»] .

Следующий код отображает TempData[«Message»] , но в конце запроса TempData[«Message»] удаляется: The following code displays TempData[«Message»] , but at the end of the request, TempData[«Message»] is deleted:

Поставщики TempData TempData providers

Поставщик TempData, основанный на файлах cookie, используется по умолчанию для хранения TempData в файлах cookie. The cookie-based TempData provider is used by default to store TempData in cookies.

Данные в файле cookie шифруются с помощью IDataProtector, кодируются с помощью Base64UrlTextEncoder, а затем фрагментируются. The cookie data is encrypted using IDataProtector, encoded with Base64UrlTextEncoder, then chunked. Так как файл cookie фрагментируется, ограничение на размер одного такого файла, заданное в ASP.NET Core 1.x, не применяется. Because the cookie is chunked, the single cookie size limit found in ASP.NET Core 1.x doesn’t apply. Данные файла cookie не сжимаются, так как сжатие зашифрованных данных может привести к проблемам с безопасностью, например атакам CRIME и BREACH. The cookie data isn’t compressed because compressing encrypted data can lead to security problems such as the CRIME and BREACH attacks. Дополнительные сведения на поставщике TempData, основанном на файлах cookie, см. в разделе CookieTempDataProvider. For more information on the cookie-based TempData provider, see CookieTempDataProvider.

Выбор поставщика TempData Choose a TempData provider

Выбор поставщика TempData включает в себя несколько аспектов: Choosing a TempData provider involves several considerations, such as:

  1. Приложение уже использует состояние сеанса? Does the app already use session state? Если это так, использование поставщика TempData для состояния сеанса не требует от приложения никаких дополнительных издержек (кроме объема данных). If so, using the session state TempData provider has no additional cost to the app (aside from the size of the data).
  2. Приложение использует TempData лишь ограниченно, для сравнительно небольших объемов данных (до 500 байт)? Does the app use TempData only sparingly for relatively small amounts of data (up to 500 bytes)? Если это так, поставщик TempData на основе файлов cookie незначительно увеличивает издержки для каждого запроса, переносящего TempData. If so, the cookie TempData provider adds a small cost to each request that carries TempData. В противном случае поставщик TempData для состояния сеанса удобно использовать, чтобы устранить круговой обход большого объема данных в каждом запросе до полного использования TempData. If not, the session state TempData provider can be beneficial to avoid round-tripping a large amount of data in each request until the TempData is consumed.
  3. Приложение выполняется на ферме серверов на нескольких серверах? Does the app run in a server farm on multiple servers? Если это так, не требуется дополнительная настройка для использования поставщика TempData для файлов cookie, за исключением защиты данных (см. статьи Защита данных в ASP.NET Core и Key storage providers in ASP.NET Core (Поставщики хранилища ключей в ASP.NET Core)). If so, there’s no additional configuration required to use the cookie TempData provider outside of Data Protection (see Защита данных в ASP.NET Core and Key storage providers).

Большинство веб-клиентов (например, веб-браузеры) налагают ограничение на максимальный размер каждого файла cookie и (или) общее количество таких файлов. Most web clients (such as web browsers) enforce limits on the maximum size of each cookie, the total number of cookies, or both. При использовании поставщика TempData на основе файлов cookie убедитесь, что приложение не нарушает эти ограничения. When using the cookie TempData provider, verify the app won’t exceed these limits. Учитывайте общий объем данных. Consider the total size of the data. Учитывайте увеличение размеров файла cookie в результате шифрования и фрагментирования. Account for increases in cookie size due to encryption and chunking.

Настройка поставщика TempData Configure the TempData provider

Поставщик TempData на основе файлов cookie включен по умолчанию. The cookie-based TempData provider is enabled by default.

Чтобы включить поставщик TempData на основе сеанса, используйте метод расширения AddSessionStateTempDataProvider: To enable the session-based TempData provider, use the AddSessionStateTempDataProvider extension method:

Порядок ПО промежуточного слоя важен. The order of middleware is important. В предыдущем примере исключение InvalidOperationException возникает при вызове UseSession после UseMvc . In the preceding example, an InvalidOperationException exception occurs when UseSession is invoked after UseMvc . Дополнительные сведения см. в разделе Порядок расположения ПО промежуточного слоя. For more information, see Middleware Ordering.

Если вы ориентируетесь на .NET Framework и используете поставщик TempData на основе сеансов, добавьте в проект пакет Microsoft.AspNetCore.Session. If targeting .NET Framework and using the session-based TempData provider, add the Microsoft.AspNetCore.Session package to the project.

Строки запроса Query strings

Вы можете передать ограниченный объем данных из одного запроса в другой, добавив их в строку запроса нового запроса. A limited amount of data can be passed from one request to another by adding it to the new request’s query string. Это удобно для захвата состояния в сохраняемом виде, что позволяет обмениваться ссылками с внедренным состоянием по электронной почте или через социальные сети. This is useful for capturing state in a persistent manner that allows links with embedded state to be shared through email or social networks. Поскольку строки запроса URL-адреса являются открытыми, никогда не используйте их для конфиденциальных данных. Because URL query strings are public, never use query strings for sensitive data.

Вдобавок к случайному раскрытию информации включение данных в строки запроса может открыть возможности для атак с подделкой межсайтовых запросов (CSRF), которые могут обманом вынудить пользователей посещать вредоносные веб-сайты во время проверки подлинности. In addition to unintended sharing, including data in query strings can create opportunities for Cross-Site Request Forgery (CSRF) attacks, which can trick users into visiting malicious sites while authenticated. Это позволит злоумышленникам похитить данные пользователей из приложения или предпринимать вредоносные действия от их имени. Attackers can then steal user data from the app or take malicious actions on behalf of the user. Любое сохраненное состояние приложения или сеанса необходимо защитить от атак CSRF. Any preserved app or session state must protect against CSRF attacks. Дополнительные сведения см. в статье Предотвращение атак с подделкой межсайтовых запросов (XSRF/CSRF). For more information, see Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks.

Скрытые поля Hidden fields

Данные можно сохранить в скрытых полях формы и опубликовать обратно при следующем запросе. Data can be saved in hidden form fields and posted back on the next request. Это типичное поведение для многостраничных форм. This is common in multi-page forms. Так как клиент может незаконно изменить данные, приложение всегда должно перепроверять данные в скрытых полях. Because the client can potentially tamper with the data, the app must always revalidate the data stored in hidden fields.

HttpContext.Items HttpContext.Items

Коллекция HttpContext.Items используется для хранения данных при обработке одного запроса. The HttpContext.Items collection is used to store data while processing a single request. Ее содержимое удаляется после обработки каждого запроса. The collection’s contents are discarded after a request is processed. Коллекцию Items часто используют для обеспечения взаимодействия компонентов или ПО промежуточного слоя, когда они выполняются в разные моменты времени во время обработки запроса и не могут передавать параметры напрямую. The Items collection is often used to allow components or middleware to communicate when they operate at different points in time during a request and have no direct way to pass parameters.

В следующем примере ПО промежуточного слоя добавляет isVerified в коллекцию Items . In the following example, middleware adds isVerified to the Items collection.

Далее в конвейере другое ПО промежуточного слоя может получить доступ к значению isVerified : Later in the pipeline, another middleware can access the value of isVerified :

Для ПО промежуточного слоя, которое используется всего одним приложением, допустимы ключи string . For middleware that’s only used by a single app, string keys are acceptable. ПО промежуточного слоя, используемое несколькими экземплярами приложения, должно использовать уникальные ключи объекта во избежание конфликтов. Middleware shared between app instances should use unique object keys to avoid key collisions. В следующем примере показано, как использовать уникальный ключ объекта, определенный в классе ПО промежуточного слоя: The following example shows how to use a unique object key defined in a middleware class:

Другой код может обратиться к значению, хранящемуся в HttpContext.Items , с помощью ключа, предоставляемого классом ПО промежуточного слоя: Other code can access the value stored in HttpContext.Items using the key exposed by the middleware class:

Данный подход также позволяет не использовать строки ключей в коде. This approach also has the advantage of eliminating the use of key strings in the code.

Кэш Cache

Кэширование — это эффективный способ хранения и извлечения данных. Caching is an efficient way to store and retrieve data. Приложение может управлять временем существования элементов кэша. The app can control the lifetime of cached items.

Кэшированные данные не связаны с конкретным запросом, пользователем или сеансом. Cached data isn’t associated with a specific request, user, or session. Будьте внимательны и не кэшируйте данные пользователя, которые можно извлечь по запросу другого пользователя. Be careful not to cache user-specific data that may be retrieved by other users’ requests.

Дополнительные сведения можно найти по адресу: Кэширование ответов в ASP.NET Core. For more information, see Кэширование ответов в ASP.NET Core.

Внедрение зависимостей Dependency Injection

Используйте внедрение зависимостей, чтобы сделать данные доступными для всех пользователей: Use Dependency Injection to make data available to all users:

Определите службу, содержащую данные. Define a service containing the data. Например, определяется класс с именем MyAppData : For example, a class named MyAppData is defined:

Добавьте класс службы в Startup.ConfigureServices : Add the service class to Startup.ConfigureServices :

Используйте класс службы данных: Consume the data service class:

Распространенные ошибки Common errors

«Unable to resolve service for type «Microsoft.Extensions.Caching.Distributed.IDistributedCache» while attempting to activate «Microsoft.AspNetCore.Session.DistributedSessionStore»» (Не удается разрешить службу для типа «Microsoft.Extensions.Caching.Distributed.IDistributedCache» при попытке активировать «Microsoft.AspNetCore.Session.DistributedSessionStore»). «Unable to resolve service for type ‘Microsoft.Extensions.Caching.Distributed.IDistributedCache’ while attempting to activate ‘Microsoft.AspNetCore.Session.DistributedSessionStore’.»

Обычно она вызвана невозможностью настройки по меньшей мере одной реализации IDistributedCache . This is usually caused by failing to configure at least one IDistributedCache implementation. Дополнительные сведения см. в разделах Распределенное кэширование в ASP.NET Core и Кэширование в памяти в ASP.NET Core. For more information, see Распределенное кэширование в ASP.NET Core and Кэширование в памяти в ASP.NET Core.

Если ПО промежуточного слоя для сеанса не удается сохранить сеанс (например, резервное хранилище недоступно), оно регистрирует исключение и запрос выполняется обычным образом. In the event that the session middleware fails to persist a session (for example, if the backing store isn’t available), the middleware logs the exception and the request continues normally. Это приводит к непредсказуемому поведению. This leads to unpredictable behavior.

Например, пользователь сохраняет корзину для покупок в сеансе. For example, a user stores a shopping cart in session. Он добавляет товар в корзину, но фиксация завершается сбоем. The user adds an item to the cart but the commit fails. Приложению неизвестно о сбое, поэтому оно сообщает пользователю, что товар добавлен в корзину, хотя это не так. The app doesn’t know about the failure so it reports to the user that the item was added to their cart, which isn’t true.

Сессия ASP.Net

Я хочу сохранить «состояние» некоторых действий, которые пользователь выполняет в серии различных веб-форм ASP.Net. Каковы мои предпочтения в отношении сохраняющегося состояния, и каковы преимущества/недостатки каждого решения?

Я использую объекты Session и используя некоторые вспомогательные методы для сильного ввода объектов:

Мне рассказывают многочисленные источники, что «Сессия зла», так что это действительно основная причина этого вопроса. Я хочу знать, что вы думаете о «лучшей практике» и почему.

В сеансовом состоянии нет ничего злонамеренного зла.

Есть несколько вещей, которые следует иметь в виду, которые могут вас укусить:

  • Если пользователь нажимает кнопку назад, вы возвращаетесь на предыдущую страницу, но состояние сеанса не возвращается. Таким образом, ваш CurrentAccount может быть не таким, каким он был на странице.
  • Процессы ASP.NET могут быть переработаны IIS. Когда это произойдет, следующий запрос начнет новый процесс. Если вы используете в состоянии сеанса процесса, по умолчанию оно не будет: — (
  • Сессия также может включать тайм-аут с тем же результатом, если пользователь неактивен в течение некоторого времени. Это значение по умолчанию составляет 20 минут, поэтому приятный обед сделает это.
  • Использование состояния сеанса процесса требует, чтобы все объекты, хранящиеся в состоянии сеанса, были сериализованы.
  • Если пользователь открывает второе окно браузера, он будет ожидать второго и отдельного приложения, но состояние сеанса, скорее всего, будет разделено между двумя. Поэтому изменение CurrentAccount в одном окне браузера сделает то же самое в другом.

Ваши два варианта временного хранения данных формы — это, во-первых, сохранение каждой информации формы в переменных (состояниях) сеанса и, во-вторых, передачу информации о форме с использованием параметров URL. Использование Cookies в качестве потенциального третьего варианта просто не работает по той простой причине, что многие из ваших посетителей, вероятно, отключили cookies (это, однако, не влияет на сеансовые куки). Кроме того, я предполагаю в силу вашего вопроса, что вы не хотите хранить эту информацию в таблице базы данных до тех пор, пока она полностью не будет выполнена.

Использование переменных (ов) сеанса является классическим решением этой проблемы, но оно имеет несколько недостатков. Среди них: (1) большие объемы данных могут использовать серверную ОЗУ, если вы используете управление сеансом inproc, (2) разделение переменных сеанса на нескольких серверах в ферме серверов требует дополнительных соображений и (3) профессионально разработанное приложение должно защищать от истечения срока действия сеанса (не просто передавать переменную сеанса и использовать ее — если срок действия сеанса истек, приведение бросает ошибку). Однако для подавляющего большинства приложений, переменные сессии, бесспорно путь.

Альтернативой является передача каждой информации формы в URL. Основная проблема с этим подходом заключается в том, что вам нужно быть предельно осторожным в отношении «прохождения» информации. Например, если вы собираете информацию на четырех страницах, вам нужно будет собрать информацию в первую очередь, передать ее в URL-адрес на вторую страницу, где вы должны сохранить ее в этом представлении. Затем, вызывая третью страницу, вы будете собирать данные формы со второй страницы плюс переменные viewstate и кодировать как в URL-адресе, так и т.д. Если у вас есть пять или более страниц или если посетитель будет прыгать по сайту, вы У тебя будет настоящий беспорядок на твоих руках. Имейте в виду также, что вся информация должна быть A) должна быть сериализована в строку с безопасным URL-адресом и B) закодирована таким образом, чтобы предотвратить простые хаки на основе URL-адресов (например, если вы поместили цену в ясный текст и передали ее вместе, кто-то может изменить цену). Обратите внимание, что вы можете уменьшить некоторые из этих проблем, создав своего рода «диспетчер сеансов» и попросите его управлять строками URL-адресов для вас, но вы все равно должны быть чрезвычайно чувствительны к тому, что любая данная ссылка может сбить кого-то всю сессию, если он не управляется должным образом.

В конце я использую переменные URL только для передачи очень ограниченных данных с одной страницы на другую (например, идентификатор элемента, закодированный в ссылке на этот элемент).

Предположим, что вы действительно будете управлять пользовательскими данными, используя встроенные возможности Session. Почему кто-то скажет вам, что «Сессия зла»? Ну, в дополнение к рассмотренной выше нагрузке на память, серверной ферме и причинам истечения, первичной критикой переменных сеанса, которые они являются, фактически, нетипизированными переменными.

К счастью, разумное использование переменных сеанса может избежать проблем с памятью (в любом случае большие базы данных должны храниться в базе данных), и если вы используете сайт, достаточно большой для работы фермы серверов, существует множество механизмов для совместного использования встроенных в ASP.NET(подсказка: вы не будете использовать хранилище inproc).

Чтобы избежать практически всех остальных недостатков сеанса, я рекомендую реализовать объект для хранения ваших данных сеанса, а также некоторые простые функции управления объектами сеанса. Затем создайте их в потомке класса «Страница» и используйте этот дочерний класс страницы для всех ваших страниц. Тогда просто получить доступ к вашим данным сеанса через класс страницы в виде набора строго типизированных значений. Обратите внимание: поля «Объекты» предоставят вам доступ к каждой из ваших «переменных сеанса» строго типизированным способом (например, по одному полю для каждой переменной).

Сообщите мне, если это простая задача для вас или вам нужен образец кода!

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL