autofac / autofac.owin Goto Github PK
View Code? Open in Web Editor NEWOWIN integration for Autofac
License: MIT License
OWIN integration for Autofac
License: MIT License
Hi guys!
Does this package only work for middleware that inherit from Microsoft.Owin.OwinMiddleware
?
Sample:
https://github.com/johnkors/Autofac.OwinMiddleware.Sample/tree/master
Just wondering, seeing as there are several ways of implementing middlewares..
http://benfoster.io/blog/how-to-write-owin-middleware-in-5-different-steps
I have a particular configuration (i.e., hosting OWIN in plain vanilla asp.net application in IIS) that requires me to "inject" ILifetimeScope
from outside OWIN middleware instead of creating it inside. So what I want to have is:
Application_BeginRequest
creates a per-request lifetime scope and saves it to HttpRequest
propertiesHttpRequest
propertiesApplication_EndRequest
gets lifetime scope from HttpRequest
properties and disposes itIs this a feasible approach? I can provide a create a pull-request for this quite quickly and I don't think this would be a breaking change.
Version 7.0.0 of Autofac was published on March 7, 2023 but it looks like Autofac.Owin is setup with an upper bound on the verions of Autofac to be less than version 7.0.0. Attemptiong to install gives the following error:
Unable to resolve dependencies. 'Autofac 7.0.0' is not compatible with 'Autofac.Owin 7.0.0 constraint: Autofac (>= 6.0.0 && < 7.0.0)'.
I'm trying to access the AutofacLifetimeScope inside the context.Response.OnSendingHeaders
event.
This event may only run a bit late on the request execution, but shouldn't it be considered still request execution?
A bit of context:
Microsoft.Owin.Security.OAuth only calls the Create providers of the codes and tokens during this event. As of now, my only solution is to create transient services and pass delegates to create the service instances on those providers so I can save the tokens and codes.
Anyway, I'm trying to change that in order to use the "normal" context per request so I don't have to open up multiple connections.
Here's an example of an owin middleware with the issue replication:
public class SimpleMiddleware : OwinMiddleware
{
private static readonly PathString Path = new PathString("/test");
public SimpleMiddleware(OwinMiddleware next) : base(next)
{
}
public async override Task Invoke(IOwinContext context)
{
if (!context.Request.Path.Equals(Path))
{
await Next.Invoke(context);
return;
}
context.Response.OnSendingHeaders(o =>
{
//scope here is already disposed
var scopeOnHeaders = context.GetAutofacLifetimeScope();
var serviceOnHeaders = scopeOnHeaders.Resolve<PluggableComponent>();
context.Response.Headers.Add("Echo", new[] { serviceOnHeaders.Echo() });
}, this);
//scope here is fine
var scope = context.GetAutofacLifetimeScope();
var service = scope.Resolve<PluggableComponent>();
var responseData = new { Date = DateTime.Now, Echo = service.Echo() };
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.ContentType = "application/json";
context.Response.Write(JsonConvert.SerializeObject(responseData));
}
}
From autofac/Autofac.WebApi.Owin#2
The PR was merged into the Web API OWIN integration but isn't Web API specific. For 4.0.0 it should move into the core OWIN integration so everyone can use it.
I see that the TFM of the nuget package is net45: https://www.nuget.org/packages/Autofac.Owin/
Is .NET Standard / .NET Core support planned? If not, do you need help for that?
Thanks,
Viktor
I would love to give a concise description of exactly what this bug is, but I don't fully understand it myself so I will instead try to explain as much of what I know about the issue and hope someone can fill in the gaps.
A web application using the Owin integration has memory leaks if it is under consistent stress which does not allow the request processing threads to exit.
LifetimeScopes are created for each request and are disposed properly when the request ends, but the LifetimeScope references are maintained and as a result garbage collection never cleans up the LifetimeScopes.
Here's a sample reference tree for one such LifetimeScope:
Rough outline of what happens to cause this issue:
I believe the ConcurrentBag which tracks the ComponentRegistrations is coming from somewhere within the Autofac 6.0 pipeline but I am not sure where.
I have attached a sample application (see below), this is just a simple Web API .NET Framework application to which I added the Owin pipeline and Autofac Owin integration.
To reproduce, just spam the application (using F5 in a browser works for me) and then take a memory dump. Don't wait too long between spamming and taking the dump or the threads will exit and the GC will clean up the ThreadLocal stuff and eventually clear out the LifetimeScopes. Inside of the memory dump, search for all instances of LifetimeScope and see that there are many hanging around and are all rooted in ConcurrentBags / ThreadLocals.
If you consistently ping the sample site for an extended period of time, you will see the number of LifetimeScopes in the memory dump continue to grow.
Under high load, the LifetimeScopes which are created by the Autofac.Owin integration should be cleaned up and released for garbage collection when the request ends.
Autofac 6.0
Autofac.Owin 6.0
I was able to work around this problem by specifically removing the OwinContext.Environment key "autofac:OwinLifetimeScope:" which removes the reference to the LifetimeScope and allows it to be garbage collected. This smells like a hack to me.
This can be found in NonAutofacMiddleware.cs inside of the sample application.
If you want to see the results in memory from running requests for an extended amount of time, I wrote a small console app to just repeatedly ping the site:
static void Main(string[] args)
{
var address = "https://localhost:44387/";
while (true)
{
Console.WriteLine($"Pinging {address} at {DateTime.Now}");
var client = new HttpClient();
var response = client.GetAsync(address).ConfigureAwait(false).GetAwaiter().GetResult();
response.EnsureSuccessStatusCode();
Thread.Sleep(300);
}
}
I'm working on an ASP.NET (not Core, but based on .NET Framework) WebAPI project. It uses Autofac for DI. I need to implement a Singleton/SingleInstance via Autofac. But the class gets instantiated for every API request. What I want is an object that exists for the entire runtime of the application and is always the same. Independent of any API request.
The controller requests the object in the constructor and Autofac properly delivers an instance of the object, but it's always a new one.
The only exception was, when I started the SingleInstance with AutoActivate it was created, then the first request got the same instance, but every following one received a new instance.
I already asked this on StackOverflow, but got no answer, so I hoped I'll find a response here. I'm thankful for any suggestions.
The class in question is named ScriptExecutionHost
. It requests only a string as a parameter and two other singletons. See below for details.
Here is the relevant code:
Startup.cs
public void Configuration(IAppBuilder app)
{
var container = ContainerConfig.Configure();
var config = GetHttpConfiguration(container);
app.UseAutofacMiddleware(container);
app.UseAutofacLifetimeScopeInjector(container);
app.UseCors(CorsOptions.AllowAll);
ConfigureOAuth(app);
#if TESTSYSTEM || DEBUG
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
SwaggerConfig.Register(config);
#endif
var physicalFileSystem = new PhysicalFileSystem("./app");
// Make ./app the default root of the static files in our Web Application.
app.UseFileServer(new FileServerOptions
{
RequestPath = new PathString(string.Empty),
EnableDirectoryBrowsing = true,
EnableDefaultFiles = true,
FileSystem = physicalFileSystem,
StaticFileOptions = { FileSystem = physicalFileSystem, ServeUnknownFileTypes = true },
DefaultFilesOptions = { DefaultFileNames = new[] { "index.html" } }
});
app.UseStageMarker(PipelineStage.MapHandler);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
private static HttpConfiguration GetHttpConfiguration(IContainer container)
{
// Create HttpConfiguration instance
var config = new HttpConfiguration
{
DependencyResolver = new AutofacWebApiDependencyResolver(container)
};
config.Formatters.Remove(config.Formatters.XmlFormatter);
// tell the application to treat dates as UTC
config.Formatters.JsonFormatter.SerializerSettings.DateTimeZoneHandling =
DateTimeZoneHandling.Utc;
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling =
ReferenceLoopHandling.Ignore;
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver =
new CamelCasePropertyNamesContractResolver();
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
"DefaultApi",
"api/{controller}/{id}",
new { id = RouteParameter.Optional }
);
return config;
}
private static void ConfigureOAuth(IAppBuilder app)
{
var oAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new AuthorizationServerProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
ContainerConfig.Configure()
public static IContainer Configure()
{
var builder = new ContainerBuilder();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Register Credentials Service
builder.Register(_ => new CredentialsService(CredentialManagerConfiguration.LoadFromWebConfig()))
.As<CredentialsService>().SingleInstance();
// Register our DatabaseContext
builder.RegisterType<DatabaseContext>().AsSelf().InstancePerRequest();
// Register the CredentialManagerConfiguration using the web.config
builder.Register(_ => CredentialManagerConfiguration.LoadFromWebConfig()).AsSelf().SingleInstance();
// Register the EmailConfiguration using the web.config
builder.Register(_ => EmailConfiguration.LoadFromWebConfig()).AsSelf().SingleInstance();
// Register the EmailClient using the EmailConfiguration from the web.config
builder.RegisterType<EmailRepo>().As<IEmailRepo>().SingleInstance();
// Register the UnitOfWork using the DatabaseContext, FileTemplates and EmailClient
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().AsSelf()
.WithParameter("templateFileFolder", _fileTemplateBaseDirectory)
.WithParameter("downloadDir", _fileDownloadBaseDirectory)
.InstancePerRequest();
builder.RegisterType<ScriptExecutionHost>().AsSelf().WithParameter("fileDownloadBaseDirectory", _fileDownloadBaseDirectory).SingleInstance().AutoActivate();
// OPTIONAL: Register the Autofac model binder provider.
builder.RegisterWebApiModelBinderProvider();
return builder.Build();
}
The relevant controllers constructor
public ScriptsController(IUnitOfWork unitOfWork, ScriptExecutionHost scriptExecutionHost) : base(unitOfWork)
{
_unitOfWork = unitOfWork;
_adService = new ActiveDirectoryService(new ActiveDirectoryConfiguration());
_scripExecutionHost = scriptExecutionHost;
}
The ScriptExecutionHost constructor
public class ScriptExecutionHost : IRegisteredObject
{
...
public ScriptExecutionHost(string fileDownloadBaseDirectory, CredentialManagerConfiguration credentialManagerConfiguration, IEmailRepo emailRepo)
{
// Register ourself to the hosting environment to be able to shut down gracefully
// This is necessary to ensure we can finish our work before the application pool is recycled
HostingEnvironment.RegisterObject(this);
_fileDownloadBaseDirectory = fileDownloadBaseDirectory;
_credentialManagerConfiguration = credentialManagerConfiguration;
_emailRepo = emailRepo;
_logger.Debug("ScriptExecutionHost initialized.");
_logger.Debug("File download base directory: {0}", _fileDownloadBaseDirectory);
// I used this to check if Autofac truly creates a new instance of this class every time.
initTime = DateTime.Now;
}
I excpect a SingleInstance to generate a singleton type object, that only exists once for the entire lifetime of the application.
Autofac: 7.0.1
Autofac.Owin: 7.1.0
Autofac.WebApi2: 6.1.1
Autofac.WebApi2.Owin: 6.2.1
CsvHelper: 30.0.1
Microsoft.AspNet.WebApi: 5.2.9
Microsoft.AspNet.WebApi.Client: 5.2.9
Microsoft.AspNet.WebApi.Core: 5.2.9
Microsoft.AspNet.WebApi.Cors: 5.2.9
Microsoft.AspNet.WebApi.Owin: 5.2.9
Microsoft.AspNet.WebApi.WebHost: 5.2.9
Microsoft.CodeDom.Providers.DotNetCompilerPlatform: 4.1.0
Microsoft.IdentityModel.JsonWebTokens: 6.30.0
Microsoft.IdentityModel.Logging: 6.30.0
Microsoft.IdentityModel.Tokens: 6.30.0
Microsoft.Owin: 4.2.2
Microsoft.Owin.Cors: 4.2.2
Microsoft.Owin.FileSystems: 4.2.2
Microsoft.Owin.Host.SystemWeb: 4.2.2
Microsoft.Owin.Security: 4.2.2
Microsoft.Owin.Security.Jwt: 4.2.2
Microsoft.Owin.Security.OAuth: 4.2.2
Microsoft.Owin.StaticFiles: 4.2.2
Microsoft.Web.Infrastructure: 2.0.0
Newtonsoft.Json: 13.0.3
NLog: 5.1.4
NLog.Web: 5.2.3
Owin: 1.0.0
Swashbuckle: 5.6.0
System.IdentityModel.Tokens.Jwt: 6.30.0
Hello!
Microsoft have just released an update of all Microsoft.Owin.* NuGet packages from 4.0.0-preview1 to 4.0.0 stable. But I can't update update to stable due to Autofac dependency (Microsoft.Owin < 4.0.0, so strictly less).
My app works fine with a current Autofac.Owin package and a preview from Microsoft, and from what I've seen they didn't introduce breaking changes in 4.0.0, so please consider validating and including 4.0.0 stable in your NuGet package dependencies.
Thanks.
I'm using Autofac.Owin to get DI features using IAppBuilder.
I created a simple DebugMiddleware which I try to resolve from Autofac container by calling the UseMiddlewareFromContainer
method.
Here's a simple code snippet:
public void Configuration(IAppBuilder application)
{
this.RegisterDependencies(); // creating Container here
application.UseMiddlewareFromContainer<DebuggingMiddleware>();
}
DebugMiddleware
is a simple OwinMiddleware
class that doesn't have any dependencies other than Microsoft.Owin
.
The problem is that the Configuration
method is not even fired on startup and the app crashes with the exception:
System.IO.FileLoadException
Could not load file or assembly 'Microsoft.Owin, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
I looked up in the source code of Autofac.Owin
, the packages.config containts a reference to Microsoft.Owin 3.0.0
even though there's >=3.0.0 on Nuget. Can this be a problem?
Basically, I can build the container in the Startup.Configuration
method and then add the Autofac middleware into the IAppBuilder
.
public void Configuration(IAppBuilder application)
{
var container = BuildContainer();
app.UseAutofacMiddleware(container);
}
I can also put the registrations into custom middlewares and register different dependencies in different middlewares based on some arguments. For example:
public class HttpClientRegistrationMiddleware : OwinMiddleware
{
private HttpClientRegistrationOptions options;
public HttpClientRegistrationMiddleware(OwinMiddleware next, HttpClientRegistrationOptions options) : base(next)
{
this.options = options;
}
public override async Task Invoke(IOwinContext context)
{
if (context.GetAutofacLifetimeScope() != null)
{
await Next.Invoke(context);
}
else
{
var builder = context.Get<ContainerBuilder>(nameof(ContainerBuilder));
builder.Register(c => options.Handler == null ? new HttpClient() : new HttpClient(options.Handler)).SingleInstance();
await Next.Invoke(context);
}
}
}
Is it a good practice? Are there any pitfalls about it?
Thank you.
If you look at the OWIN self hosting example you can see the expected output to respect the registration order of the middleware. However, when you execute the example, the middleware is executed in the opposite order:
Inside the 'Invoke' method of the 'SecondMiddleware' middleware.
Inside the 'Invoke' method of the 'FirstMiddleware' middleware.
Inside the 'OnActionExecutingAsync' method of the custom action filter.
Inside the 'Get' method of the 'TestController' controller.
Inside the 'OnActionExecutedAsync' method of the custom action filter.
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Date: Wed, 24 Nov 2021 16:21:09 GMT
Server: Microsoft-HTTPAPI/2.0
Content-Length: 15
Content-Type: application/json; charset=utf-8
}
"Hello, world!"
(Issue based on this StackOverflow question.)
Examples
repo.cd src/WebApiExample.OwinSelfHost
dotnet run
As documented, the middleware should execute in the order registered.
The logic for resolving the set of middleware items looks like it's been stable for six years. However, I recall we had to change some internals in Autofac to handle resolving IEnumerable<T>
in registration order and it involved doing things like this which reverse the order in which registrations are returned when enumerating them manually.
I'm guessing that due to that reversal in core Autofac, we also need to reverse the order in which the manual enumeration of registered middleware is handled. We probably should also add a unit test to make sure we don't regress this.
v6 Compatibility and version dependency checks ahead of release.
In my registration if I have the following the middlewares never fire.
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
owin one request autofac middleware and controller lifetime not same one
UnitOfWorkManagerMiddleware
Startup.css
/// <summary>
///
/// </summary>
public class Startup
{
/// <summary>
///
/// </summary>
public Startup()
{
}
/// <summary>
///
/// </summary>
/// <param name="app"></param>
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
config.Formatters.JsonFormatter.MediaTypeMappings.Add(new QueryStringMapping("datatype", "json", "application/json"));
config.Formatters.JsonFormatter.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings()
{
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore
};
ConfigureAutofac(app, config);
app.UseWebApi(config);
}
/// <summary>
///
/// </summary>
/// <param name="appBuilder"></param>
/// <param name="config"></param>
private static void ConfigureAutofac(IAppBuilder appBuilder, HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
#region SingleInstance
var assemblyCore = Assembly.Load("Api");
var assemblyCommon = Assembly.Load("Common");
builder.RegisterAssemblyTypes(assemblyCore, assemblyCommon)
.Where(t => t.GetCustomAttribute<SingleInstanceAttribute>() != null)
.SingleInstance();
builder.RegisterAssemblyTypes(assemblyCore, assemblyCommon)
.Where(t => t.GetCustomAttribute<SingleInstanceAttribute>() != null)
.AsImplementedInterfaces()
.SingleInstance();
#endregion
#region Repository
var assemblyRepository = Assembly.Load("Repository");
builder.RegisterAssemblyTypes(assemblyRepository)
.AsImplementedInterfaces()
.InstancePerRequest();
#endregion
#region Service
var assemblyServices = Assembly.Load("Services");
builder.RegisterAssemblyTypes(assemblyServices)
.AsImplementedInterfaces()
.InstancePerRequest();
#endregion
builder.RegisterType<UnitOfWorkManagerMiddleware>().InstancePerRequest();
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
appBuilder.UseAutofacMiddleware(container);
}
}
Middleware
/// <summary>
///
/// </summary>
public class UnitOfWorkManagerMiddleware : OwinMiddleware
{
/// <summary>
///
/// </summary>
/// <param name="next"></param>
/// <param name="unitOfWorkManager"></param>
public UnitOfWorkManagerMiddleware(OwinMiddleware next, UnitOfWorkManagerCloud unitOfWorkManager, ITemplateRepository _templateRepository, ITemplateRepository _templateRepository2) : base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
try
{
await Next.Invoke(context);
}
finally
{
TransactionalAttribute.SetUnitOfWorkManager(null);
}
}
}
Repository
public class TemplateRepository : ITemplateRepository
{
readonly string aa = Guid.NewGuid().ToString();
public TemplateRepository(UnitOfWorkManagerCloud uowm) : base(uowm)
{
}
}
public interface ITemplateRepository : IRepositoryCloud<TemplateEntity>
{
}
public class TemplateService : ITemplateService
{
private readonly ITemplateRepository _templateRepository;
private readonly ITemplateRepository _templateRepository2;
private readonly UnitOfWorkManagerCloud _uowm;
public TemplateService(ITemplateRepository templateRepository,ITemplateRepository templateRepository2, UnitOfWorkManagerCloud uowm)
{
_templateRepository = templateRepository;
_templateRepository2 = templateRepository2;
_uowm = uowm;
//TransactionalAttribute.SetUnitOfWorkManager(uowm);
}
}
public class UnitOfWorkManagerCloud
{
readonly string aa = Guid.NewGuid().ToString();
public UnitOfWorkManagerCloud()
{
}
}
owin autofac middleware and controller lifetime
same one
Put the exception with stack trace here.
Autofac: 6.4.0.0
Autofac.Integration.Owin: 7.0.0.0
Autofac.Integration.WebApi:6.1.1.0
Sample
WindowsFormsApp7.zip
I want to file this here just so that the people Googling for the symptoms will be able to find it and see the resolution
After upgrading to Autofac.Owin
7.0.0 we've observed a sizeable memory leak due to a lot of held System.Threading.ThreadLocal+LinkedSlotVolatile<System.Collections.Concurrent.ConcurrentBag+ThreadLocalList<Autofac.Core.IComponentRegistration>>
app.UseAutofacLifetimeScopeInjector(_container)
Autofac
: 6.4.0
Autofac.Owin
: 7.0.0
IAsyncDisposable
(see #29).IDisposable
to IAsyncDisposable
to dispose ILifetimeScope
IDisposable
was fixed in autofac/Autofac#1257, but the IAsyncDisposable
wasn't fixed: autofac/Autofac#1353So, to fix this, we simply need to wait for new core release, and then simply bump the required dependency version.
From @alexmg on April 2, 2014 12:1
The order of middleware is currently determined based on the order of registration. A mechanism needs to be provided to control this order. The ability to add stage markers also needs to be considered when solving this issue.
Copied from original issue: autofac/Autofac#510
Now, after we got rid of one unpleasantry, let's move to another one.
Terminal call.
app
.UseBasicAuthentication()
.Use(AuthenticatedOnly)
.Run(container.Resolve<Uploader>().InvokeAsync);
I want to be able to specify end-of-pipeline delegate (unfortunately, only delegates are allowed) without explicitly resolving the dependencies needed inside.
app.Run<Uploader>((uploader, owinContext) => uploader.InvokeAsync(owinContext));
Which should be more or less equivalent to
app.Run(owinContext =>
owinContext.GetAutofacLifetimeScope().Resolve<Uploader>().InvokeAsync(owinContext)
);
Task UploadAsync(IOwinContext, Dependency1, Dependency2);
app.Run(UploadAsync);
Equivalent to
app.Run(owinContext => {
var lifetimeScope = owinContext.GetAutofacLifetimeScope();
return UploadAsync(
owinContext,
lifetimeScope.Resolve<Dependency1>(),
lifetimeScope.Resolve<Dependency2>()
);
});
This one is actually beautiful from the user point of view - if you not take into account the necessity to provide for 15 variants of Func<Task,IOwinContext,Dependency1,...,DependencyN>
.
I could do either - or both - if you deem this appropriate.
Is there any way we can make the OwinLifetimeScopeKey configurable and/or allow for some sort of prefix?
We have a scenario where 2 different copies of Autofac are being used in the same OWIN pipeline. Given that they're using the same key for storing per-request data in the OWIN environment then we get cross-over behavior and undesirable results. Obviously the MiddlewareRegisteredKey would also be affected by this.
I can provide more contextual information if desired. Thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.