3

I am not seeing much information on porting a asp.net mvc 4.6 application to the asp.net core 2.1 Tons of 1.0 to 2.0 and 2.0. to 2.1 articles, but it is a bit steep in changes.

Ok, I have been all over google and stackoverflow and what I am trying/wanting to do is convert an older .net application and bring it into .net core.

Some big culprits I see as problems are the following:

HttpContext.Current
HttpContext.Current.Request.Url.AbsolutePath
HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)
private static string CollectionToHtmlTable(HttpCookieCollection collection)

I was seeing these articles which are helpful, but much to be desired.

https://www.carlrippon.com/httpcontext-in-asp-net-core/ https://dotnetcoretutorials.com/2017/01/05/accessing-httpcontext-asp-net-core/

Inside Controller it seems the easiest, but most of this HttpContext.Current stuff is sprinkled around various places domain libraries etc..

So in both url's above it seems that using this line below in the startup.cs however, I don't have a startup.cs outside of main asp.net core

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

Then also in startup I seen this article https://www.strathweb.com/2016/12/accessing-httpcontext-outside-of-framework-components-in-asp-net-core/

//one of many things added to project
services.AddHttpContextAccessor();

I realize that several questions have been asked in the last couple of years - here is to hoping that some brave soul has explored this stuff and has some advise/answers to how to migrate this stuff over.

Method to Port: #1

  public Service(string key, LogRecord.CallType callType, string operation, string opArg, string opResponse)
    {
        this.Key = string.IsNullOrEmpty(key)
                       ? HttpContext.Current != null ? "Inbound/WebHttp: " + HttpContext.Current.Request.Url.AbsolutePath : string.Empty
                       : key;
        this.CallType = Enum.GetName(typeof(LogRecord.CallType), callType);
        this.URL = HttpContext.Current != null && callType == LogRecord.CallType.WebHttp
                       ? HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)
                       : string.Empty;
        this.Operation = operation;
        this.OpArg = opArg;
        this.OpResponse = opResponse;
    }

Another: #2

   private static string CollectionToHtmlTable(HttpCookieCollection collection)
    {
        // Converts HttpCookieCollection to NameValueCollection
        var nvc = new NameValueCollection();
        foreach (string item in collection)
        {
            var httpCookie = collection[item];
            if (httpCookie != null)
            {
                nvc.Add(item, httpCookie.Value);
            }
        }

        return CollectionToHtmlTable(nvc);
    }
  • 4
    It's not really clear what you are asking. Do you want to inject `HttpContextAccessor` in classes in other projects? Note that `HttpContext.Current` was deprecated becuase it was wildly misused, so you should be asking yourself whether you actually need it – Camilo Terevinto Aug 07 '18 at 00:17
  • "however, I don't have a startup.cs outside of main asp.net core" - Isn't that the one you're looking for? What is the issue you're experiencing using `IHttpContextAccessor` and (possibly) `IActionContextAcccessor`? – ProgrammingLlama Aug 07 '18 at 00:17
  • @CamiloTerevinto If I wanted to port an application over - these hacks in the urls I pasted especially the strathweb one, don't have a request.Path - Needed based on all the code that previous developers wrote for services, security, error logs identity etc.. –  Aug 07 '18 at 00:25
  • @john - there is only a startup.cs file in asp.net - however I'm wanting to be in class libraries in which those methods above are not available. Looking to essentially get ported over –  Aug 07 '18 at 00:27
  • You'll have to inject `IHttpContextAccessor` where you need it. It provides `HttpContext.Request`, which contains `Scheme`, `Host.Host`, `Host.Port`, `Path`, and `QueryString` - everything you need to reconstruct the URI. – ProgrammingLlama Aug 07 '18 at 00:28
  • I will add a few methods that I have to port over. Take a lot in a few minutes or so - thx in advance –  Aug 07 '18 at 00:28
  • 1
    Do you currently use dependency injection? – ProgrammingLlama Aug 07 '18 at 00:31
  • @john Any code or url you can provide as an example ? –  Aug 07 '18 at 00:31
  • Let me know if there's anything that needs clarifying in the answer I've provided. – ProgrammingLlama Aug 07 '18 at 00:46

2 Answers2

5

The problem is, you are currently using it wrong.

Inside Controller it seems the easiest, but most of this HttpContext.Current stuff is sprinkled around various places domain libraries etc..

A Domain Libarary should be independent from the frontend. It just doesn't matter if it's a website with Session or a statefull WPF App. Or a RestFull Api.

That said, a relative Quick Fix would be to inject the HttpContext into your domain class.

public DomainService(IHttpContextAccessor httpContext)
{
    _httpContext = httpContext;
}

You can then obtain your DomainService via Dependency Injection. If the creation is complex, you are looking for a Factory.

Or you could create the Service yourself in your ActionMethod (Of course in this case you need need to change the constructor of the Service to HttpContext:

public IActionResult Foo()
{
    var service = new DomainService(HttpContext)
}

That said: it was removed for a reason. Please do not rely on HttpContext in your Domain! Create a business object and give it as parameter to the domain instead.


Not sure if it is the best way, but I have created a BusinessContext class and registered it as scoped. A factory is responsible for creating it with the needed data.


DON'T DO THIS:

If you are really crazy, maybe this could help you for migration.

Community
  • 1
  • 1
Christian Gollhardt
  • 16,510
  • 17
  • 74
  • 111
  • "Please do not rely on HttpContext in your Domain". In my case I want to add an IP address to every DB call, what is wrong with this? Do I need to collect IP addresses at every controller? – Toolkit Mar 07 '20 at 10:21
  • 1
    I mean, do not rely on it in a direct dependency. If you need the IP Adress in your Domain, create a Service which can transport the IP Adress (e.g. a `IBusinessContext` with a `IpAdress {get;}`. When you have a website, a factory creates it depending from your environment (e. g. HttpContext). This enables you to use the same domain from an WPF Application, where the IP is created from something other, than an HttpContext. @Toolkit – Christian Gollhardt Mar 11 '20 at 12:56
2

Posting this on request of OP, so it's not a full answer. You can reconstruct the URI from the IHttpContextAccessor like so:

IHttpContextAccessor context; // injected
var request = context.HttpContext.Request;

var uriBuilder = new UriBuilder();
uriBuilder.Scheme = request.Scheme;
uriBuilder.Host = request.Host.Host;
if (request.Host.Port.HasValue)
{
    uriBuilder.Port = request.Host.Port.Value;
}
uriBuilder.Path = request.Path;
if (request.QueryString.HasValue)
{
    uriBuilder.Query = request.QueryString.Value.Substring(1);
}

var requestUri = uriBuilder.Uri;

Likewise, you can access the IRequestCookieCollection via:

var collection = context.HttpContext.Request.Cookies
foreach (KeyValuePair<string, string> cookie in collection)
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
  • I think that `// injected` part is what's causing most problem for the OP. I'm pretty sure they think they cannot access the DI container outside the asp.net core project – Camilo Terevinto Aug 07 '18 at 00:36
  • @Camilio I did try and probe that with a comment but didn't get a reply on that front. Will update a little if necessary. – ProgrammingLlama Aug 07 '18 at 00:37