Reputation: 36700
We have a library which works in ASP.NET 4 and uses HttpContext.Current
. We are aware that we can't use HttpContext.Current
in ASP.NET Core but should use IHttpContextAccessor
.
How can we change this library so we both support ASP.NET 4 (by using HttpContext.Current
) and ASP.NET Core (IHttpContextAccessor
) and packaged as one NuGet package?
Upvotes: 4
Views: 1088
Reputation: 36700
The answer is that it isn't possible. The same that you can't create a one NuGet package to target both MVC1 and MVC2 (both not as Nuget package available)
Of course you could use assembly bindings, but only when there aren't breaking changes.
Microsoft is naming there ASP.NET Core packages with "AspNetCore", e.g. Microsoft.AspNetCore.Mvc vs Microsoft.AspNet.Mvc
Upvotes: 0
Reputation: 5908
If you define two target frameworks in project.json
(like aspnetcore
and net451
), then two separate dlls will be created and put into lib/aspnetcore
and lib/net451
inside the nuget package. Nuget will know which one to use, based on the target framework of the project that consumes the package.
Now, you can use #ifdef
statements in your library to distinguish, which parts of code should be compiled only for specified platforms.
A simple example:
using System;
namespace MyLib
{
#if NETFX
using HttpContext = System.Web.HttpContext;
#elif NETCORE
using HttpContext = Microsoft.AspNetCore.Http.HttpContext;
#endif
public class MyClass
{
public string GetUserAgent(HttpContext ctx)
{
return ctx.Request.Headers["User-Agent"];
}
public void WriteToResponse(HttpContext ctx, string text)
{
#if NETFX
ctx.Response.Output.Write(text);
#elif NETCORE
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
ctx.Response.Body.Write(bytes, 0, bytes.Length);
#endif
}
}
}
To make these switches work, you have to define framework-specific constants in project.json:
"frameworks": {
"netcoreapp1.0": {
"buildOptions": {
"define": [
"NETCORE"
]
},
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
},
"Microsoft.AspNetCore.Http": "1.0.0"
}
},
"net451": {
"buildOptions": {
"define": [
"NETFX"
]
},
"dependencies": {
"Microsoft.AspNet.WebApi": "5.2.3"
},
"frameworkAssemblies": {
"System.Web": "4.0.0.0"
}
}
},
Note that both frameworks have different set of dependencies. HttpContext
here will be a different type when compiled for netcoreapp and for net451. Fortunatelly, these types have very similar methods, so often times you can use them in the same way, without #ifdef
s (like in GetUserAgent
). Other times, you won't be able to avoid it (like in WriteToResponse
).
Now, in a AspNet Core project you could use this library like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (ctx, next) => {
var lib = new MyLib.MyClass();
var msg = lib.GetUserAgent(ctx);
lib.WriteToResponse(ctx, "user agent is: " + msg);
});
}
And in old AspNet MVC:
public class HomeController : Controller
{
public ActionResult Index()
{
var lib = new MyLib.MyClass();
var msg = lib.GetUserAgent(System.Web.HttpContext.Current);
lib.WriteToResponse(System.Web.HttpContext.Current, "user agent is: " + msg);
return new HttpStatusCodeResult(200);
}
}
Full source code on github.
Upvotes: 0
Reputation: 733
One possibility:
Create three libraries.
1 and 2 have the same assembly name and Factory just references either of the two.
At a time there will be only two assemblies present as reference in the folder. Factory and one among the other two in references.
Create a nuget package with all the three assemblies. 1 and 2 go in separate folders lets call it aspnet4 and aspnet5.
Package also contains target file which is used by aspnet projects. The target file copies factory and one of the libraries into the references folder depending upon a property present in aspnet project. This property could be something like aspnet=aspnet5.
This might be a too big thing and simpler solution might exist. I will think of a simpler solution.
//4. AspNetUsageBaseClass Assembly
namespace AspNetUsage
{
//rest of code
public abstract AspNetUsageBaseClass
{
//rest of code
public abstract void HttpContextIHttpContextAccessor();
}
}
//1. AspNetUsage Assembly, Reference AspNetUsageBaseClass Assembly
using AspNetUsage;
public class AspNetUsage:AspNetUsageBaseClass
{
public override void HttpContextIHttpContextAccessor()
{
//HttpContext based code
}
}
//2. AspNetUsage Assembly, Reference AspNetUsageBaseClass Assembly
using AspNetUsage;
public class AspNetUsage:AspNetUsageBaseClass
{
public override void HttpContextIHttpContextAccessor()
{
//IHttpContextAccessor based code
}
}
Now there will be in total 3 assemblies. One base class assembly. Two others implementing specific functionality. Inside nuget package structure should be:
AspNetUsageBaseClass.dll
- base class assembly
AspNet4\AspNetUsage.dll
- HttpContext assembly
AspNet5OrCore\AspNetUsage.dll
- IHttpContextAccessor assembly
AspNet.target
- This will be imported in asp net project and depending on the value of the property extract one of the two dlls.
Inside AspNet project you would have:
AspNetUsageBaseClass context = new AspNetUsage();
context.HttpContextIHttpContextAccessor();
This is not Factory
pattern based but this can be extended to Factory
pattern based with some modification.
There might be some mistakes as I have used notepad to type the logic in absence of VS.
Upvotes: 1