[AspNet Core] Nuget proxy website, aspnetnuget
Because access to Nuget is too slow, before the release of Dotnet Core RC2, I made a Nuget proxy Website Based on Asp. Net.
This is the website address: http://nuget.lzzy.net/
Source: http://nuget.lzzy.net/api/v2
Guangxi Telecom's mbps bandwidth.
This website will cache all the accessed API pages and packages.
The principle of API page caching. The first access will wait for the server to download the page information from Nuget.
After the download, the URL is replaced and saved to the database.
The second access will retrieve the page from the database to determine the expiration time.
If it has expired, the page information is returned first, and a new thread in the background downloads the new page.
In this way, access in China will feel very fast.
Upgrade to AspNet Core
After RC2 was released, I thought it was time to study the Dotnet Core platform.
Let's start with this small Nuget proxy website.
Under. Net FX, the developed proxy program uses IHttpHandler for proxy.
Then the AspNet Core becomes proxy through middleware.
The routes are also different in AspNetCore, which is easier to use than the old version.
Use of routes
Note: The Microsoft. AspNetCore. Routing package is required for Routing.
First, create a static class and add a UseXXXMiddleware extension method. This is the Convention for AspNetCore to use middleware. Of course, you can also use another name.
In the method, we need a new RouteBuilder instance.
Call various ing methods in the instance.
Call the Build method of RouteBuilder to generate a route.
Finally, use the extension method UseRouter of routing middleware to pass the route just built as a parameter.
public static IApplicationBuilder UseNugetProxyMiddleware(this IApplicationBuilder builder, IConfigurationRoot config) { if (!Directory.Exists("Packages")) Directory.CreateDirectory("Packages"); var cacheSection = config.GetSection("Cache"); _CacheMetadata = int.Parse(cacheSection.GetSection("Metadata").Value); _CacheList = int.Parse(cacheSection.GetSection("List").Value); _CacheDetail = int.Parse(cacheSection.GetSection("Detail").Value); _CacheDefault = int.Parse(cacheSection.GetSection("Default").Value); var proxySection = config.GetSection("Proxy"); _Source = proxySection.GetSection("Source").Value; _Replace = proxySection.GetSection("Replace").Value; _Path = proxySection.GetSection("Path").Value; var routeBuilder = new RouteBuilder(builder); routeBuilder.MapGet(_Path + "/{action}", PageHandler); routeBuilder.MapGet(_Path, PageHandler); routeBuilder.MapGet(_Path + "/package/{id}/{version}", PackageHandler); _Path = "/" + _Path; var router = routeBuilder.Build(); return builder.UseRouter(router); } private static async Task PageHandler(HttpContext httpContext) { }
Middleware usage under Routing
When using RouteBuilder's ing method, you need to pass the delegate for processing HttpContext
The middleware method of AspNet Core is actually the same.
However, we need to obtain various data in the method, instead of getting some services in the constructor like the AspNet Core middleware.
The AspNet Core route provides an extension method GetRouteValue for HttpContext to obtain route parameters.
private static async Task PackageHandler(HttpContext httpContext) { string id = httpContext.GetRouteValue("id") as string; string version = httpContext.GetRouteValue("version") as string; }
The GetRouteData extension method is also available, which is not required here.
EntityFramework Core
In RC2, the use of EntityFramework Core has changed.
In Startup. cs, configure EF Core
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddDbContext<DataContext>(builder => { builder.UseSqlServer(Configuration.GetConnectionString("DataContext")); }); }
Modify the configuration of DbContext here.
It should be noted that the class that inherits DbContext should use constructors with parameters and call the base class constructor.
public class DataContext : DbContext { public DataContext(DbContextOptions<DataContext> options) : base(options) { } public DbSet<Page> Page { get; set; } }
Mutex lock
When multiple users access the same new page, only one person can download the data of the new page, while others will wait. The same applies to new packages.
When multiple users access the same expiration page, only one new thread is created to download the data on the new page.
The project encapsulates a SynchronizationHelp class, which is mutually exclusive in the middleware through the path.
There is nothing special to say about the rest, some of which are in the source code.
Github
Here is Github of this proxy Website:
Https://github.com/Kation/NugetProxy
Ah, by the way, there is another point.
Configure the proxy website.
Configuration file:
{ "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Debug", "System": "Information", "Microsoft": "Information" } }, "ConnectionStrings": { "DataContext": "server=(local);database=nuget;uid=sa;pwd=123@abc" }, "Cache": { "Metadata": "10080", "List": "60", "Detail": "1440", "Default": "30" }, "Proxy": { "Source": "https://www.nuget.org/api/v2", "Replace": "https://www.nuget.org/api/v2", "Path": "api/v2" }}
You can set the cache time to download the new page only after the time is exceeded. The unit is minutes.
The Source of the Proxy is the Nuget Source.
Replace is the string to be replaced and will be replaced with the current website address + Path
PS: I have a 20 m VPS reverse proxy Nuget in the United States.
Http://nuget.lzzy.net/api/v2use the source of my VPs direction proxy
The effect is faster than accessing Nuget directly ......