1

There is a problem using DryIOC in a ASP.Net WebForms application that uses Task.Run() to run some code in other threads. We encountered the problem that we can not benefit both HttpContextScopeContext and ThreadScopeContext in our ASP.Net WebForms application. We tested every Reuse scope and it did not work simultaneously. We have some Http Handlers and in their codes these does not work and our injected services are not resolved. The link to the test project is Here . The question is that how we can use DryIOC in such a way that we can have Scoped services and in Thread services (To be resolved in Task.Run() ) at the same time.

and we encounter the error message : DryIoc.ContainerException: 'code: Error.NoCurrentScope; message: No current scope is available - probably you are registering to or resolving from outside of the scope. It also may be because of the scoped dependency has singletons in its parent chain so the dependency is resolved from the root container resolver. Current resolver context is: container with ambient DryIoc.ThreadScopeContext without scope with Rules without {ThrowOnRegisteringDisposableTransient}.'

I appreciate your help.

Best regards.

We developed a sample WebForms application and tested the things we knew, but it did not work. We expect that we can have both Scoped lifetime in our Web Pages and resolve our services in Task.Run() codes too.

Masud Safari
  • 108
  • 8

1 Answers1

-1

The only advice I have here is that you have to be aware of how web pages work, and the so-called lifecycle of how web server’s work.

Remember, web development = state less!

That means that after the code behind runs, then the page is send back to the client side, and on the server that web page, the code behind, and the HTTP context is now destroyed, is disposed, and goes out of scope. The page class, the code behind, the variables, and HTTP context is NOW GONE!

When a user hits a button on a web page, the web page is sent up to the server. This is the start of the so called round-trip. A new instance of the page class is created, all variables in that page class now start from scratch (they start over teach time the page is sent up to the server).

At this point, your code behind runs, and can modify the DOM of that web page on the server. Once that code is complete, then the page is sent back to the client side. On the server side, that page class as noted is disposed, removed from memory. The web server is now waiting for ANY user to click a button and post-back. However, the server has ZERO knowledge of what the client-side browser is doing. The user can turn off their computer. They can use their browser to start shopping on Amazon.com. Your server has no knowledge of this fact, and there is no persisting HTTP context or ANYTHING at all occurring server side.

So, the page life cycle (a round trip) looks like this:

enter image description here

Note how your page class - code behind is NOT in memory on the server.

YOU DO NOT have this:

enter image description here

So, the web server is just waiting for ANY user to post-back a web page. Each user does NOT have some copy of their page, or code, or variables in memory. Each user does NOT have an existing http context here. You have ONE http context, and ONLY one DURING the time that the page is being processed by the server.

So, the user clicks a button, start of the page life cycle.

This:

enter image description here

Our web page is sent up to the server. THEN http context now exists, and ONLY will exist for a short time.

enter image description here

NOW an instance of the page class is created, and your code behind starts running.

Your code behind can modify controls (even controls to be visible or not), but the page is NOT interacting with the user - ONLY code can MODIFY the web page (user does not see one change, or many changes).

So, one change, or MANY changes to the web page can occur, but AS YOU update things like a text box etc., the user does NOT see these changes just yet. So, if you run a loop 1 to 10, and update a text box, the txt box WILL be updated 1 to 10. However, the end user sees nothing, since that web page (and code) is running up on the server.

Changes to web page are occurring on the server - the client-side browser does not have the web page any more! As your server code behind runs, and updates the DOM in the browser? The end user just sees that “spinner” and the browser is waiting. The end user does not at this point in time see ANY changes made to the browser.

Once ALL of your code is done running, then and ONLY then does the page make the trip back to the client-side browser.

The server-side class instance and code (and variables) are TOSSED OUT - DOES NOT exist! Your server-side page class is disposed - removed from memory, and the web page code behind does NOT exist any more in memory, nor in any context at all here.

So, page travels back to the client side, is re-displayed, JavaScript is loaded, and THEN JavaScript starts running. So even the client side page now 100% re-loads.

enter image description here

So, now armed with the above knowledge of a post back and round type (the page life cycle)?

So, from code behind, you CAN start whole new separate thread, and have that code run 100% independent of the web page. However, there is NOT an existing HTTP context, and the page code behind DOES NOT exist anymore ONCE the page has been sent back to the client. The web server is now waiting to process any web page from any user. Code behind does NOT exist for each user. You have one server, and ONE http context here.

So, while you are free to start a new process thread independent of the code behind and page class for that one web page? The code for the web page, and the HTTP context for that page, and the variables behind in that web page class? They have a VERY short lifespan, and ONLY exist during the short time the page was up on the server. As noted, the instant the page travels back to the client is also when all of the code, their variables, and the HTTP context now goes out of scope. The web server is now waiting to receive and process any incoming page from any user. And when that occurs is ONLY when the http context comes into existence.

So, in web land, you don't have "memory" or "variables" for each user. You have one web server, and one set of code behind that runs. Once that page processing is complete for the one request and the page life cycle is done? Then that user's context, and code is tossed out of memory, and the class and variables are disposed. And that includes the http context here (it is also gone!!!).

So, you can start a new tread/task. However, such a thread and task will not have any knowledge of any one user. It will have to be an 100% independent chuck of code, and one that has no UI or no interaction with a specific user. And such code does not have any http context.

Now, armed with the above knowledge?

You clearly can't pass a HTTP context to a separate new process thread, since the users code, the web page, and that page class code behind all go out of scope the VERY instant the code behind is done and the page is sent back to the client side.

This of course means that these worker process or separate threads you start can't use nor have a HTTP context, since the HTTP context goes out of scope rather fast and is very short lived.

If you need process code, or server code to push out notifications to each web user (or all of them), then you can introduce a web socket, and keep and force a live connection from the web server to the client browser.

Of course, setting up a custom web socket can be boatloads of work. So, most people tend to adopt an existing framework where all of the code and parts for the web socket from server to client is written for you.

A common framework for allowing real-time updates of the client-side browser based on this concept is called SignalR, and you can read about this concept here:

https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr

The above thus keeps a live network (web socket) connection open to the browser, and thus you can build real time browser update systems in which you don't have to worry about the HTTP context going out of scope. Thus, use of SignalR allows you to build and have server-side code run and push out information or notifications to the client-side browser, and do so without an existing HTTP context which as I noted goes out of scope VERY fast, and is VERY short lived.

The above explains your error. That error is that your http context goes out of scope rather fast, and is rather short lived. In other words, you are free to create a new separate task, but those tasks can't and will not have any http context available due to the state-less nature of web pages. You can of course have a web page "inquire" about the status of a separate task thread you started. You could do this by updating values in a database, and then have the web page during it's short server side life-cycle query those database values. Or you could have that separate task update values in session() of which again the web page code behind could enquire about.

Or, as suggested, you could setup and create a web socket which then allows the client side browser to maintain a network connection to the server (thus consider SignalR).

Albert D. Kallal
  • 42,205
  • 3
  • 34
  • 51
  • 1
    @albert-d-kallal Thank you for your detailed answer. But it does not cover my question as I asked about DryIoc when runing code in Task.Run() in an HttpHandler or as Web Forms Page, although we have an HttpContext in both cases. The problem is that as I understood, we can not configure DryIoc such that it handles HttpContext scoped and multithreading scopes simultaneously. We are looking for how we can handle it in DryIoc in a WebForms project. Regards. – Masud Safari Aug 05 '23 at 09:36
  • You can't and don't have httpcontext in task run. So, if you going to attempt a dependency to any class code (Dryloc), then you can't. OR you can have web page wait and stay up on the server until any dependent code has completed. You asked why you don't have httpcontext in those tasks, and I explained that you don't and in general can't do this. So, as long as we are crystal clear and your question is why can't or don't you have httpcontext in that separate code? Then sure, you are fine and ok. Don't confuse the web threaded model with that vast difference of of running a separate task. – Albert D. Kallal Aug 05 '23 at 13:00
  • So, you can have all the dependencies in your code you want (Dryloc), but any of that code will not and does not have any http context. So, if above does not answer your question, then ANY issue of you asking why no httpcontext here does not make sense. If ANY of that code does not need, nor have, or require httpcontext? Then sure, my explain does not help, but then again, that means you have no question in regards to why such code has no httpcontext, and yet in your question you clearly ask why you don't? And the above explains why this is so and that such code has no httpcontext. – Albert D. Kallal Aug 05 '23 at 13:04
  • You can pass a httpcontext to a separate task, but the calling code (the httphandler) then MUST wait for that task to complete. If such code does not wait then code is not viable. Unless the calling code waits, then such code can't be used, nor can the calling code go out of scope. This explains the difference between threading and parallel processing: https://stackoverflow.com/questions/806499/threading-vs-parallelism-how-do-they-differ#:~:text=Threading%20has%20nothing%20to%20do%20with%20parallelism%20and,complete%20ALL%20their%20actions%20any%20faster%20in%20total. – Albert D. Kallal Aug 05 '23 at 13:23
  • @albert-d-kallal Thanks for your replies. I understand your meaning. However, The problem is that I am looking for a way on how DryIoc is to be configured so that it can handle the existing DI in the context of a web page request lifecycle, and the code that runs in Task.Run(). DryIoc has a ThreadScopeContext, but when a Container is created by configuring it to understand HttpContext to create scopes per request, It can not simultaneously have a ThreadScopeContext, or may be it can, but I don't know how to configure to support both scenarios simultaneously. This is the problem I have. – Masud Safari Aug 05 '23 at 13:28
  • @albert-d-kallal I encourage you to look into the code I have provided the link in the question. – Masud Safari Aug 05 '23 at 13:29