{"id":13429508,"url":"https://github.com/neuecc/LightNode","last_synced_at":"2025-03-16T03:31:47.037Z","repository":{"id":64936434,"uuid":"14985736","full_name":"neuecc/LightNode","owner":"neuecc","description":"Micro RPC/REST Framework built on OWIN","archived":true,"fork":false,"pushed_at":"2018-01-26T18:33:35.000Z","size":6085,"stargazers_count":180,"open_issues_count":7,"forks_count":33,"subscribers_count":20,"default_branch":"master","last_synced_at":"2024-05-29T08:50:54.702Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://neuecc.github.io/LightNode","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neuecc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-12-06T15:12:23.000Z","updated_at":"2024-05-12T07:09:55.000Z","dependencies_parsed_at":"2022-12-18T21:57:05.627Z","dependency_job_id":null,"html_url":"https://github.com/neuecc/LightNode","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuecc%2FLightNode","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuecc%2FLightNode/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuecc%2FLightNode/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuecc%2FLightNode/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neuecc","download_url":"https://codeload.github.com/neuecc/LightNode/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243822310,"owners_count":20353496,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T02:00:40.919Z","updated_at":"2025-03-16T03:31:47.024Z","avatar_url":"https://github.com/neuecc.png","language":"C#","readme":"LightNode\n=========\nLightNode is a Micro RPC/REST Framework built on OWIN. LightNode is a good alternative to the ASP.NET Web API and Nancy if you make a simple API. It is like Ruby's [Grape](https://github.com/intridea/grape) framework, [Slack API](https://api.slack.com/web)'s HTTP RPC-style methods. Implementation of the API is lightweight, powerful debugging supports with [Glimpse](http://getglimpse.com/), client code generation by T4 for PCL(HttpClient) and Unity3D.  \n\nUpdate(2016-07-28), for ASP.NET Core\n---\nLightNode 2 has been started. You can install from `-Pre` packages.\n\n```\nPM\u003e Install-Package LightNode -Pre\n```\n\nSimple ASP.NET Core Startup\n\n```csharp\nusing LightNode;\n\npublic class Startup\n{\n    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)\n    {\n        app.UseLightNode(typeof(Startup));\n    }\n}\n```\n\nLightNode 2 includes swagger package. You can map for Swagger.\n\n```csharp\npublic class Startup\n{\n    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)\n    {\n        app.Map(\"/api\", builder =\u003e\n        {\n            builder.UseLightNode(typeof(Startup));\n        });\n\n        app.Map(\"/swagger\", builder =\u003e\n        {\n            var xmlName = \"AspNetCoreSample.xml\";\n            var xmlPath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), xmlName);\n\n            builder.UseLightNodeSwagger(new LightNode.Swagger.SwaggerOptions(\"AspNetCoreSample\", \"/api\")\n            {\n                XmlDocumentPath = xmlPath,\n                IsEmitEnumAsString = true\n            });\n        });\n    }\n}\n```\n\nInstallation\n---\nbinary from NuGet, [LightNode.Server](https://nuget.org/packages/LightNode.Server/)\n\n```\nPM\u003e Install-Package LightNode.Server\n```\n\nImplement Server\n---\nServer implementation is very easy, built up Owin and implements `LightNodeContract`.\n\n```csharp\n// Owin Startup\npublic class Startup\n{\n    public void Configuration(IAppBuilder app)\n    {\n        app.UseLightNode();\n    }\n}\n\n// implement LightNodeContract, all public methods become API.\n// You can access {ClassName}/{MethodName}\n// Ex. http://localhost/My/Echo?x=test\npublic class My : LightNodeContract\n{\n    // return value is response body serialized by ContentTypeFormatter(default is JSON).    \n    public string Echo(string x)\n    {\n        return x;\n    }\n\n    // support async! return type allows void, T, Task and Task\u003cT\u003e.\n    // parameter supports array, nullable and optional parameter.\n    public Task\u003cint\u003e Sum(int x, int? y, int z = 1000)\n    {\n        return Task.Run(() =\u003e x + y.Value + z);\n    }\n}\n```\n\nCompile, run, very quick! LightNode calls class as Contract, method as Operation.\n\n\u003e Parameter model bindings supports only basic pattern, can't use complex type. allow types are \"string, DateTime, DateTimeOffset, Boolean, Decimal, Char, TimeSpan, Int16, Int32, Int64, UInt16, UInt32, UInt64, Single, Double, SByte, Byte, Enum and each Nullable types and array(except byte[]. If you want to use byte[], use Base64 string instead of byte[] or see [receive byte[] section](#receiveor-send-byte))\n\n\u003e Return type allows all serializable(ContentFormatter support) type.\n\nFilter\n---\nLightNode supports filter. The implementation is like middleware pipeline.\n\n![lightnode_performance](https://f.cloud.github.com/assets/46207/1902207/3dbe3012-7c6f-11e3-8d39-7e442e92b970.jpg)\n\n```csharp\npublic class SampleFilterAttribute : LightNodeFilterAttribute\n{\n    public override async Task Invoke(OperationContext operationContext, Func\u003cTask\u003e next)\n    {\n        try\n        {\n            // OnBeforeAction\n\n            await next(); // next filter or operation handler\n\n            // OnAfterAction\n        }\n        catch\n        {\n            // OnExeception\n        }\n        finally\n        {\n            // OnFinally\n        }\n    }\n}\n```\n\nFilter can be attached contract(class), operation(method) and global. Execution pipeline is formed is sorted by Order all specified. Range is -int.MaxValue to int.MaxValue. Default Order of all filters is int.MaxValue.\n\nDifference between Middleware and Filter is who knows operation context. Filter is located after the parameter binding. Therefore, it is possible check attributes(`operationContext.IsAttributeDefined`, `operationContext.GetAttributes`).\n\nControl StatusCode\n---\nThe default status code, can't find operation returns 404, failed operation returns 500, success and has value returns 200, success and no value returns 204. If returns arbitrary status code, throw `ReturnStatusCodeException`.\n\n```csharp\nthrow new ReturnStatusCodeException(System.Net.HttpStatusCode.Unauthorized);\n```\n\nGlimpse plugin\n---\nLightNode fully supports [Glimpse](http://getglimpse.com/)! Currently Glimpse does not support Owin but if you host on `Microsoft.Owin.Host.SystemWeb` Glimpse works. You can download Glimpse plugin from NuGet. \n\n* PM\u003e Install-Package [Glimpse.LightNode](https://nuget.org/packages/Glimpse.LightNode/)\n\nThere are configuration sample.\n\n```csharp\npublic void Configuration(Owin.IAppBuilder app)\n{\n    app.EnableGlimpse(); // This is Glimpse.LightNode's helper for enable Glimpse\n    app.MapWhen(x =\u003e !x.Request.Path.Value.StartsWith(\"/glimpse.axd\", StringComparison.OrdinalIgnoreCase), x =\u003e\n    {\n        x.UseLightNode(new LightNodeOptions()\n        {\n            // for Glimpse Profiling\n            OperationCoordinatorFactory = new GlimpseProfilingOperationCoordinatorFactory()\n        });\n    });\n}\n```\n\nAccess glimpse.axd and Click Standalone Glimpse Launch Now! Click History window and Inspect. You can see Filter and Execution elapsed on Timeline tab.\n\n![](https://raw.githubusercontent.com/neuecc/LightNode/master/Img/glimpse_lightnode_timeline.jpg)\n\nCheck the LightNode tab, you can monitor everything. Parameters, Result, Exectuion Phase, Response, and LightNodeOptions.\n\n![](https://raw.githubusercontent.com/neuecc/LightNode/master/Img/lightnode_glimpse_infotab.jpg)\n\nIf encounts exception, LightNode tab shows exception on Result.\n\n![](https://raw.githubusercontent.com/neuecc/LightNode/master/Img/glimpse_infotab_exception.jpg)\n\nMy recommended glimpse configuration.\n\n```xml\n\u003c!-- sometimes Glimpse rewrite response for display tab, but API no needs, set RuntimePolicy PersitResults --\u003e\n\u003cglimpse defaultRuntimePolicy=\"PersistResults\" endpointBaseUri=\"~/Glimpse.axd\"\u003e\n    \u003ctabs\u003e\n        \u003cignoredTypes\u003e\n            \u003c!-- no needs only Owin --\u003e\n            \u003cadd type=\"Glimpse.AspNet.Tab.Cache, Glimpse.AspNet\" /\u003e\n            \u003cadd type=\"Glimpse.AspNet.Tab.Routes, Glimpse.AspNet\" /\u003e\n            \u003cadd type=\"Glimpse.AspNet.Tab.Session, Glimpse.AspNet\" /\u003e\n        \u003c/ignoredTypes\u003e\n    \u003c/tabs\u003e\n    \u003cruntimePolicies\u003e\n        \u003cignoredTypes\u003e\n            \u003c!-- If API's client no use cookie, ignore control cookie --\u003e\n            \u003cadd type=\"Glimpse.Core.Policy.ControlCookiePolicy, Glimpse.Core\" /\u003e\n            \u003c!-- for improvement LightNode debugging --\u003e\n            \u003cadd type=\"Glimpse.Core.Policy.StatusCodePolicy, Glimpse.Core\" /\u003e\n            \u003c!-- If not Ajax --\u003e\n            \u003cadd type=\"Glimpse.Core.Policy.AjaxPolicy, Glimpse.Core\" /\u003e\n            \u003c!-- If run on remote --\u003e\n            \u003cadd type=\"Glimpse.AspNet.Policy.LocalPolicy, Glimpse.AspNet\" /\u003e\n        \u003c/ignoredTypes\u003e\n    \u003c/runtimePolicies\u003e\n\u003c/glimpse\u003e\n```\n\nIgnore ControlCookiePolicy is very important. But we can't indistinguishable request. Glimpse handle group by cookie. You can add glimpseid cookie for example \n\n```csharp\nvar req = WebRequest.CreateHttp(\"http://localhost:41932/Member/Random?seed=13\");\n\nreq.CookieContainer = new CookieContainer();\nreq.CookieContainer.Add(new Uri(\"http://localhost:41932\"), new Cookie(\"glimpseid\", \"UserId:4\"));\n```\n![](https://raw.githubusercontent.com/neuecc/LightNode/master/Img/glimpse_history_clientgrouping.jpg)\n\nSwagger Integration\n---\nLightNode supports [Swagger](http://swagger.io/) for API Explorer(currently Swagger supports is experimental, only shows parameters).\n\n![](https://raw.githubusercontent.com/neuecc/LightNode/master/Img/swagger_support.jpg)\n\nMiddleware available in NuGet.\n\n* PM\u003e Install-Package [LightNode.Swagger](https://nuget.org/packages/LightNode.Swagger/)\n\nSwagger-UI file is embedded in LightNode.Swagger. You can enable only `UseLightNodeSwagger`.\n\n```csharp\n// Currently LightNode.Swagger only supports POST so you needs AcceptVerbs.Post\napp.Map(\"/api\", builder =\u003e\n{\n    builder.UseLightNode(new LightNodeOptions(AcceptVerbs.Get | AcceptVerbs.Post, new JilContentFormatter(), new GZipJilContentFormatter())\n    {\n        ParameterEnumAllowsFieldNameParse = true, // If you want to use enums human readable display on Swagger, set to true\n        ErrorHandlingPolicy = ErrorHandlingPolicy.ReturnInternalServerErrorIncludeErrorDetails,\n        OperationMissingHandlingPolicy = OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails\n    });\n});\n\n// Mapping to swagger path\napp.Map(\"/swagger\", builder =\u003e\n{\n    // If you want to additional info for Swagger, load xmlDoc file.\n    // LightNode.Swagger loads methods's summary, remarks, param for info.     \n    var xmlName = \"LightNode.Sample.GlimpseUse.xml\";\n    var xmlPath = System.AppDomain.CurrentDomain.BaseDirectory + \"\\\\bin\\\\\" + xmlName; // or HttpContext.Current.Server.MapPath(\"~/bin/\" + xmlName);\n\n    builder.UseLightNodeSwagger(new Swagger.SwaggerOptions(\"LightNodeSample\", \"/api\") // baseApi is LightNode's root\n    {\n        XmlDocumentPath = xmlPath,\n        IsEmitEnumAsString = true\n    });\n});\n```\n\nOkay, for example jump to `http://localhost:41932/Swagger/`, you can see all API info and Swagger specification json can download from `api-default.json`. If you host multiple LightNode engine, you can select target engine from `{engineID}.json`. `{engineID}` is from `ILightNodeOptions.ServerEngineId`.\n\nIf you can't run swagger on hosting IIS, maybe conflicts static file handling. Please remoe StaticFile handler and register OwinHttpHandler for all paths.\n\n```csharp\n\u003csystem.webServer\u003e\n    \u003chandlers\u003e\n        \u003cremove name=\"StaticFile\" /\u003e\n        \u003c!-- If use with Glimpse, glimpse handler must be first --\u003e\n        \u003cadd name=\"Glimpse\" path=\"glimpse.axd\" verb=\"GET\" type=\"Glimpse.AspNet.HttpHandler, Glimpse.AspNet\" preCondition=\"integratedMode\" /\u003e\n        \u003cadd name=\"OWIN\" path=\"*\" verb=\"*\" type=\"Microsoft.Owin.Host.SystemWeb.OwinHttpHandler\" /\u003e\n    \u003c/handlers\u003e\n\u003c/system.webServer\u003e\n```\n\nIf you want to customize index.html(or others) for authentication etc. You can use `ResolveCustomResource`.\n\n```csharp\napp.Map(\"/swagger\", builder =\u003e\n{\n    builder.UseLightNodeSwagger(new LightNode.Swagger.SwaggerOptions(\"MySample\", \"/api\")\n    {\n        ResolveCustomResource = (filePath, loadedEmbeddedBytes) =\u003e\n        {\n            if (filePath == \"index.html\")\n            {\n                using (var resourceStream = typeof(Startup).Assembly.GetManifestResourceStream(\"MySample.Swagger.index.html\"))\n                using (var ms = new MemoryStream())\n                {\n                    resourceStream.CopyTo(ms);\n                    return ms.ToArray();\n                }\n            }\n            return loadedEmbeddedBytes;\n        }\n    });\n});\n```\n\nwith ASP.NET MVC\n---\nYou can use LightNode with ASP.NET MVC. A simple solution is to change the root path.\n\n```csharp\npublic void Configuration(IAppBuilder app)\n{\n    app.Map(\"/api\",  x =\u003e\n    {\n        x.UseLightNode();\n    });\n}\n```\n\nMore ContentFormatter\n---\nDefault content formatter is `JavaScriptContentFormatter`(application/json) and bundling formatters are `TextContentFormatter`(text/plain), `HtmlContentFormatter`(text/html), `RawOctetStreamContentFormatter`(application/octet-straem), `XmlContentFormatter`(application/xml), `DataContractContentFormatter`(application/xml), `DataContractJsonContentFormatter`(application/json).\n\nMore useful ContentFormatters(for JsonNet(JSON), Jil(JSON/JSON+GZip), Jil+LZ4, ProtoBuf, MsgPack) are available.\n\n* PM\u003e Install-Package [LightNode.Formatter.JsonNet](https://nuget.org/packages/LightNode.Formatter.JsonNet/)\n* PM\u003e Install-Package [LightNode.Formatter.Jil](https://nuget.org/packages/LightNode.Formatter.Jil/)\n* PM\u003e Install-Package [LightNode.Formatter.Jil.LZ4](https://nuget.org/packages/LightNode.Formatter.Jil.LZ4/) \n* PM\u003e Install-Package [LightNode.Formatter.ProtoBuf](https://nuget.org/packages/LightNode.Formatter.ProtoBuf/)\n* PM\u003e Install-Package [LightNode.Formatter.MsgPack](https://nuget.org/packages/LightNode.Formatter.MsgPack/)\n\nConfiguration sample\n\n```csharp\npublic class Startup\n{\n    public void Configuration(Owin.IAppBuilder app)\n    {\n        // default is Json, If Accept-Encoding=gzip then Json+GZip\n        app.UseLightNode(new LightNodeOptions(AcceptVerbs.Get | AcceptVerbs.Post,\n            new JilContentFormatter(), new GZipJilContentFormatter()));\n    }\n}\n\npublic class Sample : LightNodeContract\n{\n    // use specified content formatter, select verb per operation\n    [OperationOption(AcceptVerbs.Get, typeof(HtmlContentFormatterFactory))]\n    public string Html()\n    {\n        return \"\u003chtml\u003e\u003cbody\u003eaaa\u003c/body\u003e\u003c/html\u003e\";\n    }\n    \n    // LightNode's default is GET | POST and default can customize.\n    // change per operation verb by OperationOption(AcceptVerbs)\n    // [Get/Post/Put/Delete/Patch]Attribute for its shortcut\n    [Post]\n    public int PostOnly()\n    {\n        return 0;\n    }\n}\n```\n\nReceive(or Send) byte[]\n---\nLightNode isn't allow byte[] argument. If you want to receive byte[] that use Base64 string instead of byte[]. But you needs to avoid Base64, you can take raw stream from `Environment`.\n\n```csharp\n[Post, IgnoreClientGenerate]\npublic int PostByte() // zero argument\n{\n    // Take raw stream\n    var body = this.Environment[\"owin.RequestBody\"] as Stream;\n    byte[] bodyBytes;\n    using (var ms = new MemoryStream())\n    {\n        body.CopyTo(ms);\n        bodyBytes = ms.ToArray();\n    }\n    return bodyBytes.Length;\n}\n```\n\nIf you want to receive `multipart/form-data`, you can parse by [ReadAsMultipartAsync](https://msdn.microsoft.com/ja-jp/library/hh944544.aspx) of `System.Net.Http.Formatting.dll`. \n\n```csharp\nvar body = this.Environment[\"owin.RequestBody\"] as Stream;\nvar multipart = await new StreamContent(body).ReadAsMultipartAsync();\n```\n\nIf you return byte[] array, you maybe should avoid Json(or other) ContentFormatter. You can use `RawOctetStreamContentFormatterFactory`.\n\n```csharp\n[IgnoreClientGenerate]\n[OperationOption(AcceptVerbs.Post, typeof(RawOctetStreamContentFormatterFactory))]\npublic byte[] EchoByte()\n{\n    var body = this.Environment[\"owin.RequestBody\"] as Stream;\n    byte[] bodyBytes;\n    using (var ms = new MemoryStream())\n    {\n        body.CopyTo(ms);\n        bodyBytes = ms.ToArray();\n    }\n    return bodyBytes;\n}\n```\n\nReturn HTML\n---\nIf you needs return html, set content formatter to `HtmlContentFormatter/HtmlContentFormatterFactory`. If you needs template engine, you can use [RazorEngine](https://github.com/Antaris/RazorEngine). Simple helper base contract.\n\n```csharp\npublic abstract class RazorContractBase : LightNode.Server.LightNodeContract\n{\n    static readonly IRazorEngineService razor = CreateRazorEngineService();\n\n    IRazorEngineService CreateRazorEngineService()\n    {\n        var config = new TemplateServiceConfiguration();\n        config.DisableTempFileLocking = true;\n        config.CachingProvider = new DefaultCachingProvider(_ =\u003e { });\n        config.TemplateManager = new DelegateTemplateManager(name =\u003e\n        {\n            // import from \"Views\" directory\n            var viewPath = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, \"Views\", name);\n            return System.IO.File.ReadAllText(viewPath);\n        });\n        return RazorEngineService.Create(config);\n    }\n\n    protected string View(string viewName)\n    {\n        return View(viewName, new object());\n    }\n\n    protected string View(string viewName, object model)\n    {\n        var type = model.GetType();\n        if (razor.IsTemplateCached(viewName, type))\n        {\n            return razor.Run(viewName, type, model);\n        }\n        else\n        {\n            return razor.RunCompile(viewName, type, model);\n        }\n    }\n}\n```\n\nAnd you can make shortcut of OperationOptionAttribute.\n\n```\npublic class Html : LightNode.Server.OperationOptionAttribute\n{\n    public Html(AcceptVerbs acceptVerbs = AcceptVerbs.Get | AcceptVerbs.Post)\n        : base(acceptVerbs, typeof(HtmlContentFormatterFactory))\n    {\n\n    }\n}\n```\n\nLanguage Interoperability\n---\nLightNode is like RPC but REST. Public API follows a simple rule. Address is `{ClassName}/{MethodName}`, and it's case insensitive. GET parameter use QueryString. POST parameter use x-www-form-urlencoded. Response type follows configured ContentFormatter. Receiver can select response type use url extension(.xml, .json etc...) or Accept header.\n\nAuthentication, Session, Caching, Routing, Versioning, etc\n---\nYou can use other OWIN Middleware(for example [ASP.NET Identity](http://www.asp.net/identity)). LightNode can copmose with there. LightNode provides only core framework.\n\nLightNode can enable per assembly. For the versioning strategy with project separating.  \n\n```csharp\napp.Map(\"/v1\", x =\u003e\n{\n    x.UseLightNode(new LightNodeOptions(), typeof(v1Contract).Assembly);\n});\n\napp.Map(\"/v2\", x =\u003e\n{\n    x.UseLightNode(new LightNodeOptions(), typeof(v2Contract).Assembly);\n});\n```\n\nClient code generation\n--- \nClient side implementation of the REST API is often painful. LightNode solves by T4 code generation.\n\n```csharp\n// Open .tt file and configure four steps.\n\n\u003c#@ assembly name=\"$(SolutionDir)\\Performance\\LightNode.Performance\\bin\\LightNode.Performance.dll\" #\u003e\n\u003c#\n    // ------------- T4 Configuration ------------- //\n    \n    // 1. Set LightNodeContract assemblies(and all dependency) path to above #@ assembly name # directive\n\n    // 2. Set Namespace \u0026 ClientName \u0026 Namespace\n    var clientName = \"LightNodeClient\";\n    var namespaceName = \"LightNode.Client\";\n\n    // 3. Set DefaultContentFormatter Construct String\n    var defaultContentFormatter = \"new LightNode.Formatter.JsonNetContentFormatter()\";\n\n    // 4. Set Additional using Namespace\n    var usingNamespaces = new [] {\"System.Linq\"};\n\n    // 5. Set append \"Async\" suffix to method name(ex: CalcAsync or Calc)\n    var addAsyncSuffix = true;\n\n    // ----------End T4 Configuration ------------- //\n```\n\n```csharp\n// generated code is like RPC Style.\n// {ClassName}.{MethodName}({Parameters}) \n\nvar client = new LightNodeClient(\"http://localhost\");\nawait client.Me.EchoAsync(\"test\");\nvar sum = await client.Me.SumAsync(1, 10, 100);\n```\n\nClient is very simple but very easy for use. Currently code generation provides for Portable Class Library(HttpClinet) and Unity3D(with [UniRx](https://github.com/neuecc/UniRx)).\n\nYou can download from NuGet. \n\n* PM\u003e Install-Package [LightNode.Client.PCL.T4](https://nuget.org/packages/LightNode.Client.PCL.T4/)\n* PM\u003e Install-Package [LightNode.Client.UniRx.T4](https://nuget.org/packages/LightNode.Client.UniRx.T4/)\n\nNote:Client generation currently supports POST only. \n\nDiagnostics\n---\nLightNode expose logging interface `ILightNodeOptions.Logger` and provides optional logger for [Systen.Diagnostics.Tracing.EventSource](https://msdn.microsoft.com/ja-jp/library/system.diagnostics.tracing.eventsource.aspx), it's send to ETW(EventTrace for Windows) and you can subscribe easily by Microsoft's [Semantic Logging Application Block](https://github.com/mspnp/semantic-logging)\n Library.\n \n* PM\u003e Install-Package [LightNode.Diagnostics.EventSource](https://nuget.org/packages/LightNode.Diagnostics.EventSource/)\n\n```csharp\nvar option = new LightNodeOptions\n{\n    Logger = LightNode.Diagnostics.LightNodeEventSource.Log\n};\napp.UseLightNode(option);\n```\n \nIf throws unhandled exception, LightNode's default no handles exception and pass thru other middleware. This option is useful for debugging with Glimpse or other diagnostics middleware such as Microsoft.Owin.Diagnostics's  UseErrorPage. You can also use LightNode's Builtin diagnostics system -  LightNodeOptions.ErrorHandlingPolicy `ErrorHandlingPolicy.ReturnInternalServerErrorIncludeErrorDetails`. It's show simply error string.\n\nIf LightNode can't create OperationContext(for example 404), default returns StatusCode and description string. This can customize `OperationMissingHandlingPolicy`, If `ThrowException` then throws `OperationNotFoundException`.\n\n```csharp\n// Default\nvar option = new LightNodeOptions()\n{\n    ErrorHandlingPolicy = ErrorHandlingPolicy.ThrowException,\n    OperationMissingHandlingPolicy = OperationMissingHandlingPolicy.ReturnErrorStatusCodeIncludeErrorDetails,\n};\napp.UseLightNode(option);\n```\n \nPerformance\n---\nLightNode is fastest framework.\n\n![lightnode_performance](https://f.cloud.github.com/assets/46207/1902439/a0a19c5c-7c72-11e3-9bea-244ac00dcd87.jpg)\n\nPerformance source code is in [LightNode/Performance](https://github.com/neuecc/LightNode/tree/master/Performance). Enviroment is \"Windows 8.1/CPU Core i7-3770K(3.5GHz)/Memory 32GB\" and disabled firewall and windows defender. Orange and Green bar is hosted on IIS(System.Web). LightNode(Green bar)'s performance is nearly raw handler. Gray bar is reference, LightNode on [Helios - Microsoft.Owin.Host.IIS](http://www.nuget.org/packages/Microsoft.Owin.Host.IIS/) gots extremely performance. \n\nBuild/Test Status\n---\n[![Build status](https://ci.appveyor.com/api/projects/status/i7smkb51sr0ghy15)](https://ci.appveyor.com/project/neuecc/lightnode)\n\nLightNode is using [AppVeyor](http://www.appveyor.com/) CI. You can check unit test status.\n\nReleaseNote\n---\n1.6.6.1, 2.0.4-beta\n* Add byte[] support with MultiPartContent\n\n1.6.5.1, 2.0.3-beta\n* Add PassThroughWhenStatusCodesAre option\n\n2.0.0-beta - 2016-07/28\n* ASP.NET Core support\n\n1.6.4 - 2015-11-27\n* Only LightNode.Swagger, fix doesn't show swagger when with selfhost\n\n1.6.3 - 2015-10-06\n* Add ReturnStatusCodeException(EnvironmentEmitter)\n* Add DebugOnlyClientGenerateAttribute\n* Fix DefaultParameter for bool create True/False\n\n1.6.2(Only LightNode.MsgPack) - 2015-08-18\n* Fix MsgPackFormatter when Serialize null then throws Exception\n* Update dependency to MsgPack-CLI 0.6.1\n\n1.6.1 - 2015-08-11\n* Fix when Contract's return type Task\u003cT\u003e and return with WhenAll directly throws exception\n\n1.6.0 - 2015-07-16\n* Fix '+' character in parameter decode to space(this is breaking changes but important bug)\n\n1.5.0 - 2015-06-25\n* Update Swagger-UI(array parameter, Get parameter)\n* Changed All ContentFormatter's Encoding from UTF8 with BOM to UTF8 without BOM \n* Allow multiple HTTP attributes\n* Allow OperationOptionAttribute to Class \n* Fix shows valid message when use invalid argument \n\n1.4.0 - 2015-05-05\n* Fix NegotiateFormat accepts all HTTP format specification\n* MsgPack: UnpackFrom has to be done after once Read, thanks @azyobuzin\n* Add ILightNodeOptions.Logger, split LightNodeEventSource to LightNode.Diagnostics.EventSource\n \n1.3.2(Only LightNode.Client.PCL.T4) - 2015-05-01\n* Fix LightNode.Client.PCL.T4 can't post\n\n1.3.0/1.3.1 - 2015-04-28\n* Add ReturnStatusCodeException accepts object and contentFormatter\n* Add Swagger output Get/Post/Put/Patch/Delete\n* Fix Swagger can't generate when xml comment has method overload\n* Changed InjectCustomResource -\u003e ResolveCustomResource\n* Docs Return html with RazorEngine tips\n\n1.2.1 - 2015-04-22\n* Fix LightNode.Server throws exception if run on SelfHost\n\n1.2.0 - 2015-04-19\n* Add LightNode.Swagger\n* Add LightNodeServerMiddleware.GetRegisteredHandlersInfo\n* Changed JilContentFormatter namespace \n* Fix UniRx.T4 LightNodeClient\n\n1.1.0 - 2015-02-21\n* Add AcceptVerbs.Put/Delete/Patch \n* Add HttpVerbAttributes([GET/POST/Put/Delete/Patch]Attribute)\n\n1.0.0 - 2015-02-16\n* Add Glimpse.LightNode\n* Add LightNode.Formatter.Jil\n* Add LightNode.Formatter.Jil.LZ4\n* Add LightNodeOptions.OperationCoordinatorFactory\n* ContentFormatter supports handling ContentEncoding\n* More LightNodeEventSource logging  \n\n0.4.0 - 2015-01-27\n* Add UniRx T4 Template\n* Add LightNodeEventSource logging\n* Add IgnoreClientGenerateAttribute\n* Add LightNodeOptions.OperationMissingHandlingPolicy\n* Add OperationOptionAttribute\n* Fix failed assembly load when depend assembly is not found\n* CodeGenerate ignore Abstract Contract\n* Improvement perforamnce\n\n0.3.0 - 2014-05-12\n* Add Unity T4 Template\n* Some fixes for PCL.T4 Template\n* Add default UseLightNode overload\n\n0.2.0 - 2014-01-14\n* Add Filter System\n* Enum Binding Performance Improvement\n* Strict parse for Enum\n* Parameter String disallows null at default\n* IContentFormatter needs Encoding\n* IContentFormatter.Ext can add multiple ext by \"|\" separater\n* Fixed T4 ClientCode generation\n* Return 204 when operation is void or Task\n* Return Arbitrary StatusCode that throws ReturnStatusCodeException\n* Add IgnoreOperationAttribute\n\n0.1.1 - 2013-12-23  \n* First Release\n","funding_links":[],"categories":["Frameworks, Libraries and Tools","框架, 库和工具","API"],"sub_categories":["API"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneuecc%2FLightNode","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneuecc%2FLightNode","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneuecc%2FLightNode/lists"}