For accessing data:
For data like Server.Identity.Name, I think collecting that information beforehand and passing it to your async code is a good approach. Its good decoupling as that code now only depends on those few properties.
For accessing behavior:
How are you using threads with ASP.NET? The two approaches that work are to implement and register IAsyncHttpHandler, or you're call Page.AddOnPreRenderCompleteAsync() from some ASP.NET page.
For IAsyncHttpHandler, the callback you implement is passed an HttpContext. You should be able to use that referenced context from any thread until you indicate to ASP.NET that request processing has finished. Of course you should only use that reference from one thread a time.
For Page.AddOnPreRenderCompleteAsync, it should be safe to call Page.Context from your callbacks under the same conditions.
For the existing code you have in App_Code that uses HttpContext.Current, you need to refactor that so the code takes the HttpContext as an input parameter. Existing code can pass in HttpContext.Current, new code you're writing from threads can pass in one of the contexts described earlier in this answer.