diff --git a/src/Samples/Playground/Program.cs b/src/Samples/Playground/Program.cs index 58f8fbba..1522b113 100644 --- a/src/Samples/Playground/Program.cs +++ b/src/Samples/Playground/Program.cs @@ -1,90 +1,89 @@ using System; -using System.Reflection; +using System.Linq; using System.Threading.Tasks; -using Twino.Ioc; +using Twino.MQ.Data; +using Twino.Mvc; +using Twino.Mvc.Controllers; +using Twino.Mvc.Controllers.Parameters; +using Twino.Mvc.Filters.Route; +using Twino.Protocols.TMQ; +using Twino.Server; namespace Playground { - - interface IService1 + public class Login { - void Test1(); + public string User { get; set; } + public string Pass { get; set; } } - interface IService2 + public class User { - void Test2(); + public string Name { get; set; } + public string Lastname { get; set; } } - class Service1 : IService1 + [Route("x")] + public class BController : TwinoController { - - public void Test1() + [HttpGet("c/{?x}")] + public async Task C(string x) { - Console.WriteLine("echo 1"); + return await StringAsync("Xhello: " + x); } - } - class Service2 : IService2 - { - public void Test2() - { } - } + [HttpGet("")] + public async Task B() + { + return await StringAsync("Xhello"); + } - interface IService3 { } - class Service3 : IService3 - { - public Service3(IService1 service1) + [HttpGet("d")] + public async Task D() { - service1.Test1(); + return await StringAsync("Xhello D"); } } - class Service1Proxy : IServiceProxy + + [Route("")] + public class AController : TwinoController { - private IService2 _service2; - public Service1Proxy(IService2 service2) + [HttpGet("c/{?x}")] + public async Task C(string x) { - _service2 = service2; + return await StringAsync("hello: " + x); } - public object Proxy(object decorated) + [HttpGet("")] + public async Task B() { - return DenemeDispatchProxy.Create((IService1)decorated, _service2); + return await StringAsync("hello"); } - } - - class DenemeDispatchProxy : DispatchProxy - { - private T _decorated; - private IService2 _service2; - public static T Create(T decorated, IService2 service2) + [HttpGet("d")] + public async Task D() { - object proxy = Create>(); - DenemeDispatchProxy instance = (DenemeDispatchProxy)proxy; - instance._decorated = decorated; - instance._service2 = service2; - return (T)proxy; + return await StringAsync("hello D"); } - protected override object Invoke(MethodInfo targetMethod, object[] args) + [HttpGet("e/{x}")] + public async Task E(string x) { - Console.WriteLine("PROXY"); - return targetMethod.Invoke(_decorated, args); + return await StringAsync("hello E: " + x); } } class Program { - static async Task Main(string[] args) + static void Main(string[] args) { - var container = new ServiceContainer(); - container.AddSingleton(); - container.AddSingleton(); - container.AddSingleton(); - var instance3 = await container.Get(container.CreateScope()); - Console.ReadLine(); + TwinoMvc mvc = new TwinoMvc(); + mvc.Init(); + TwinoServer server = new TwinoServer(); + server.UseMvc(mvc); + server.Start(26222); + server.BlockWhileRunning(); } } } \ No newline at end of file diff --git a/src/Samples/Sample.Mvc/Controller/AuthController.cs b/src/Samples/Sample.Mvc/Controller/AuthController.cs index 7aa2acbe..f8bc263e 100644 --- a/src/Samples/Sample.Mvc/Controller/AuthController.cs +++ b/src/Samples/Sample.Mvc/Controller/AuthController.cs @@ -40,7 +40,7 @@ public IActionResult IT() } [HttpPost("post")] - public async Task Post([FromBody] LoginModel model) + public async Task Post([FromForm] LoginModel model) { return await JsonAsync(new { diff --git a/src/Samples/Sample.Mvc/Controller/HomeController.cs b/src/Samples/Sample.Mvc/Controller/HomeController.cs index 7af9ecc7..03c56c94 100644 --- a/src/Samples/Sample.Mvc/Controller/HomeController.cs +++ b/src/Samples/Sample.Mvc/Controller/HomeController.cs @@ -6,10 +6,10 @@ namespace Sample.Mvc.Controller { - [Route("")] + [Route("a")] public class HomeController : TwinoController { - [HttpGet("")] + [HttpGet("b")] public async Task Get() { return await StringAsync("Welcome!"); diff --git a/src/Tests/Test.Mvc/Controllers/TestControllers.cs b/src/Tests/Test.Mvc/Controllers/TestControllers.cs new file mode 100644 index 00000000..e9585cbc --- /dev/null +++ b/src/Tests/Test.Mvc/Controllers/TestControllers.cs @@ -0,0 +1,146 @@ +using System.Threading.Tasks; +using Twino.Mvc; +using Twino.Mvc.Controllers; +using Twino.Mvc.Filters.Route; + +namespace Test.Mvc.Controllers +{ + [Route("")] + [Route("test")] + [Route("[controller]")] + public class Test1Controller : TwinoController + { + [HttpGet("")] + public async Task IndexGet() + { + return await StringAsync("get/"); + } + + [HttpPost("")] + public async Task IndexPost() + { + return await StringAsync("post/"); + } + + [HttpGet("a")] + public async Task GetA() + { + return await StringAsync("geta/"); + } + + [HttpPost("a")] + public async Task PostA() + { + return await StringAsync("posta/"); + } + + [HttpGet("b/{?x}")] + public async Task GetB(string x) + { + return await StringAsync($"getb/{x}"); + } + + [HttpPost("b/{?x}")] + public async Task PostB(string x) + { + return await StringAsync($"postb/{x}"); + } + + [HttpGet("c/{x}")] + public async Task GetC(string x) + { + return await StringAsync($"getc/{x}"); + } + + [HttpPost("c/{x}")] + public async Task PostC(string x) + { + return await StringAsync($"postc/{x}"); + } + + [HttpGet("d/{x}/{?y}")] + public async Task GetD(string x, string y) + { + return await StringAsync($"getd/{x}/{y}"); + } + + [HttpPost("d/{x}/{?y}")] + public async Task PostD(string x, string y) + { + return await StringAsync($"postd/{x}/{y}"); + } + + [HttpGet("e/{x}/{y}")] + public async Task GetE(string x, string y) + { + return await StringAsync($"gete/{x}/{y}"); + } + + [HttpPost("e/{x}/{y}")] + public async Task PostE(string x, string y) + { + return await StringAsync($"poste/{x}/{y}"); + } + + + [HttpGet("[action]")] + public async Task GetAA() + { + return await StringAsync("geta/"); + } + + [HttpPost("[action]")] + public async Task PostAA() + { + return await StringAsync("posta/"); + } + + [HttpGet("[action]/{?x}")] + public async Task GetBB(string x) + { + return await StringAsync($"getb/{x}"); + } + + [HttpPost("[action]/{?x}")] + public async Task PostBB(string x) + { + return await StringAsync($"postb/{x}"); + } + + [HttpGet("[action]/{x}")] + public async Task GetCC(string x) + { + return await StringAsync($"getc/{x}"); + } + + [HttpPost("[action]/{x}")] + public async Task PostCC(string x) + { + return await StringAsync($"postc/{x}"); + } + + [HttpGet("[action]/{x}/{?y}")] + public async Task GetDD(string x, string y) + { + return await StringAsync($"getd/{x}/{y}"); + } + + [HttpPost("[action]/{x}/{?y}")] + public async Task PostDD(string x, string y) + { + return await StringAsync($"postd/{x}/{y}"); + } + + [HttpGet("[action]/{x}/{y}")] + public async Task GetEE(string x, string y) + { + return await StringAsync($"gete/{x}/{y}"); + } + + [HttpPost("[action]/{x}/{y}")] + public async Task PostEE(string x, string y) + { + return await StringAsync($"poste/{x}/{y}"); + } + } +} \ No newline at end of file diff --git a/src/Tests/Test.Mvc/RoutingTest.cs b/src/Tests/Test.Mvc/RoutingTest.cs index 269875bc..364ccd4d 100644 --- a/src/Tests/Test.Mvc/RoutingTest.cs +++ b/src/Tests/Test.Mvc/RoutingTest.cs @@ -1,10 +1,121 @@ +using FluentAssertions; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Twino.Mvc; +using Twino.Mvc.Controllers; +using Twino.Mvc.Routing; +using Twino.Protocols.Http; +using Xunit; + namespace Test.Mvc { public class RoutingTest { - /* - * controller: plain, [ name ], { parameter }, multiple bindings, nested / - * - */ + [Theory] + [InlineData("GET", "/", "get/")] + [InlineData("POST", "/", "post/")] + [InlineData("GET", "/a", "geta/")] + [InlineData("POST", "/a", "posta/")] + [InlineData("GET", "/b/3", "getb/3")] + [InlineData("POST", "/b/3", "postb/3")] + [InlineData("GET", "/b", "getb/")] + [InlineData("POST", "/b", "postb/")] + [InlineData("GET", "/c/4", "getc/4")] + [InlineData("POST", "/c/4", "postc/4")] + [InlineData("GET", "/d/5", "getd/5/")] + [InlineData("POST", "/d/5", "postd/5/")] + [InlineData("GET", "/e/6/7", "gete/6/7")] + [InlineData("POST", "/e/6/7", "poste/6/7")] + [InlineData("GET", "/getaa", "geta/")] + [InlineData("POST", "/postaa", "posta/")] + [InlineData("GET", "/getbb/3", "getb/3")] + [InlineData("POST", "/postbb/3", "postb/3")] + [InlineData("GET", "/getbb", "getb/")] + [InlineData("POST", "/postbb", "postb/")] + [InlineData("GET", "/getcc/4", "getc/4")] + [InlineData("POST", "/postcc/4", "postc/4")] + [InlineData("GET", "/getdd/5", "getd/5/")] + [InlineData("POST", "/postdd/5", "postd/5/")] + [InlineData("GET", "/getee/6/7", "gete/6/7")] + [InlineData("POST", "/postee/6/7", "poste/6/7")] + [InlineData("GET", "/test", "get/")] + [InlineData("POST", "/test", "post/")] + [InlineData("GET", "/test/a", "geta/")] + [InlineData("POST", "/test/a", "posta/")] + [InlineData("GET", "/test/b/3", "getb/3")] + [InlineData("POST", "/test/b/3", "postb/3")] + [InlineData("GET", "/test/b", "getb/")] + [InlineData("POST", "/test/b", "postb/")] + [InlineData("GET", "/test/c/4", "getc/4")] + [InlineData("POST", "/test/c/4", "postc/4")] + [InlineData("GET", "/test/d/5", "getd/5/")] + [InlineData("POST", "/test/d/5", "postd/5/")] + [InlineData("GET", "/test/e/6/7", "gete/6/7")] + [InlineData("POST", "/test/e/6/7", "poste/6/7")] + [InlineData("GET", "/test/getaa", "geta/")] + [InlineData("POST", "/test/postaa", "posta/")] + [InlineData("GET", "/test/getbb/3", "getb/3")] + [InlineData("POST", "/test/postbb/3", "postb/3")] + [InlineData("GET", "/test/getbb", "getb/")] + [InlineData("POST", "/test/postbb", "postb/")] + [InlineData("GET", "/test/getcc/4", "getc/4")] + [InlineData("POST", "/test/postcc/4", "postc/4")] + [InlineData("GET", "/test/getdd/5", "getd/5/")] + [InlineData("POST", "/test/postdd/5", "postd/5/")] + [InlineData("GET", "/test/getee/6/7", "gete/6/7")] + [InlineData("POST", "/test/postee/6/7", "poste/6/7")] + [InlineData("GET", "/test1", "get/")] + [InlineData("POST", "/test1", "post/")] + [InlineData("GET", "/test1/a", "geta/")] + [InlineData("POST", "/test1/a", "posta/")] + [InlineData("GET", "/test1/b/3", "getb/3")] + [InlineData("POST", "/test1/b/3", "postb/3")] + [InlineData("GET", "/test1/b", "getb/")] + [InlineData("POST", "/test1/b", "postb/")] + [InlineData("GET", "/test1/c/4", "getc/4")] + [InlineData("POST", "/test1/c/4", "postc/4")] + [InlineData("GET", "/test1/d/5", "getd/5/")] + [InlineData("POST", "/test1/d/5", "postd/5/")] + [InlineData("GET", "/test1/e/6/7", "gete/6/7")] + [InlineData("POST", "/test1/e/6/7", "poste/6/7")] + [InlineData("GET", "/test1/getaa", "geta/")] + [InlineData("POST", "/test1/postaa", "posta/")] + [InlineData("GET", "/test1/getbb/3", "getb/3")] + [InlineData("POST", "/test1/postbb/3", "postb/3")] + [InlineData("GET", "/test1/getbb", "getb/")] + [InlineData("POST", "/test1/postbb", "postb/")] + [InlineData("GET", "/test1/getcc/4", "getc/4")] + [InlineData("POST", "/test1/postcc/4", "postc/4")] + [InlineData("GET", "/test1/getdd/5", "getd/5/")] + [InlineData("POST", "/test1/postdd/5", "postd/5/")] + [InlineData("GET", "/test1/getee/6/7", "gete/6/7")] + [InlineData("POST", "/test1/postee/6/7", "poste/6/7")] + public async Task FindRoutes(string method, string path, string aResult) + { + TwinoMvc mvc = new TwinoMvc(); + mvc.Init(); + mvc.CreateRoutes(Assembly.GetExecutingAssembly()); + + HttpRequest request = new HttpRequest(); + request.Method = method; + request.Path = path; + + HttpResponse response = new HttpResponse(); + + RouteMatch match = mvc.RouteFinder.Find(mvc.Routes, request); + Assert.NotNull(match); + + TwinoController controller = await mvc.ControllerFactory.CreateInstance(mvc, match.Route.ControllerType, request, response, mvc.Services.CreateScope()); + + var parameters = MvcConnectionHandler.FillParameters(request, match).Select(x => x.Value).ToArray(); + Task task = (Task)match.Route.ActionType.Invoke(controller, parameters); + + IActionResult result = task.Result; + string url = Encoding.UTF8.GetString(((MemoryStream)result.Stream).ToArray()); + url.Should().Be(aResult); + } } } \ No newline at end of file diff --git a/src/Tests/Test.Mvc/Test.Mvc.csproj b/src/Tests/Test.Mvc/Test.Mvc.csproj index fdc35d75..5ebb2e45 100644 --- a/src/Tests/Test.Mvc/Test.Mvc.csproj +++ b/src/Tests/Test.Mvc/Test.Mvc.csproj @@ -9,6 +9,7 @@ + diff --git a/src/Twino.Client.Connectors/Twino.Client.Connectors.csproj b/src/Twino.Client.Connectors/Twino.Client.Connectors.csproj index 04801e4b..e28a606d 100644 --- a/src/Twino.Client.Connectors/Twino.Client.Connectors.csproj +++ b/src/Twino.Client.Connectors/Twino.Client.Connectors.csproj @@ -6,9 +6,9 @@ Twino.Client.Connectors Connectors for twino WebSocket and TMQ protocols twino,server,client,connector,websocket,tmq - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Client.TMQ/Twino.Client.TMQ.csproj b/src/Twino.Client.TMQ/Twino.Client.TMQ.csproj index 8eafcbd5..6adecc99 100644 --- a/src/Twino.Client.TMQ/Twino.Client.TMQ.csproj +++ b/src/Twino.Client.TMQ/Twino.Client.TMQ.csproj @@ -6,9 +6,9 @@ Twino.Client.TMQ Twino Messaging Queue Client to connect all TMQ Servers twino,tmq,client,mq,messaging,queue - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Client.WebSocket/Twino.Client.WebSocket.csproj b/src/Twino.Client.WebSocket/Twino.Client.WebSocket.csproj index ee933c91..c13d3dfc 100644 --- a/src/Twino.Client.WebSocket/Twino.Client.WebSocket.csproj +++ b/src/Twino.Client.WebSocket/Twino.Client.WebSocket.csproj @@ -6,9 +6,9 @@ Twino.Client.WebSocket Twino WebSocket Client to connect all WebSocket servers twino,websocket,client - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Core/Twino.Core.csproj b/src/Twino.Core/Twino.Core.csproj index e15bdf2c..bdeb2782 100644 --- a/src/Twino.Core/Twino.Core.csproj +++ b/src/Twino.Core/Twino.Core.csproj @@ -6,9 +6,9 @@ Twino.Core Twino Core library for all twino servers, protocols and services twino,server,core - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Core/obj/Release/netcoreapp3.0/Twino.Core.AssemblyInfo.cs b/src/Twino.Core/obj/Release/netcoreapp3.0/Twino.Core.AssemblyInfo.cs index 7c725436..2007dd4f 100644 --- a/src/Twino.Core/obj/Release/netcoreapp3.0/Twino.Core.AssemblyInfo.cs +++ b/src/Twino.Core/obj/Release/netcoreapp3.0/Twino.Core.AssemblyInfo.cs @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -13,11 +14,11 @@ [assembly: System.Reflection.AssemblyCompanyAttribute("Mehmet Helvacıköylü")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyDescriptionAttribute("Twino Core library for all twino servers, protocols and services")] -[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.14")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyProductAttribute("Twino.Core")] [assembly: System.Reflection.AssemblyTitleAttribute("Twino.Core")] -[assembly: System.Reflection.AssemblyVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyVersionAttribute("2.7.14")] // Generated by the MSBuild WriteCodeFragment class. diff --git a/src/Twino.Extensions.Data/Twino.Extensions.Data.csproj b/src/Twino.Extensions.Data/Twino.Extensions.Data.csproj index ce360212..e266471e 100644 --- a/src/Twino.Extensions.Data/Twino.Extensions.Data.csproj +++ b/src/Twino.Extensions.Data/Twino.Extensions.Data.csproj @@ -6,9 +6,9 @@ Twino.Extensions.Data Entity Framework Core Data Context extension for Twino IOC twino,entity,framework,data,context,factory,ioc,service - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Extensions.Http/Twino.Extensions.Http.csproj b/src/Twino.Extensions.Http/Twino.Extensions.Http.csproj index 6a9d1dac..0761b539 100644 --- a/src/Twino.Extensions.Http/Twino.Extensions.Http.csproj +++ b/src/Twino.Extensions.Http/Twino.Extensions.Http.csproj @@ -6,9 +6,9 @@ Twino.Extensions.Http HttpClient Factory extension for Twino IOC twino,http,client,factory,ioc,dependency,injection,service - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Extensions.Http/obj/Release/netcoreapp3.0/Twino.Extensions.Http.AssemblyInfo.cs b/src/Twino.Extensions.Http/obj/Release/netcoreapp3.0/Twino.Extensions.Http.AssemblyInfo.cs index 83422910..798b01c8 100644 --- a/src/Twino.Extensions.Http/obj/Release/netcoreapp3.0/Twino.Extensions.Http.AssemblyInfo.cs +++ b/src/Twino.Extensions.Http/obj/Release/netcoreapp3.0/Twino.Extensions.Http.AssemblyInfo.cs @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -13,11 +14,11 @@ [assembly: System.Reflection.AssemblyCompanyAttribute("Mehmet Helvacıköylü")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyDescriptionAttribute("HttpClient Factory extension for Twino IOC")] -[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.14")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyProductAttribute("Twino.Extensions.Http")] [assembly: System.Reflection.AssemblyTitleAttribute("Twino.Extensions.Http")] -[assembly: System.Reflection.AssemblyVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyVersionAttribute("2.7.14")] // Generated by the MSBuild WriteCodeFragment class. diff --git a/src/Twino.Ioc/Twino.Ioc.csproj b/src/Twino.Ioc/Twino.Ioc.csproj index 97c1b98e..ca72c0e0 100644 --- a/src/Twino.Ioc/Twino.Ioc.csproj +++ b/src/Twino.Ioc/Twino.Ioc.csproj @@ -6,9 +6,9 @@ Twino.Ioc Twino IOC Service containers and scopes twino,ioc,dependency,injection,service,container,scope - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Ioc/obj/Release/netcoreapp3.0/Twino.Ioc.AssemblyInfo.cs b/src/Twino.Ioc/obj/Release/netcoreapp3.0/Twino.Ioc.AssemblyInfo.cs index 096f8f4b..dbb03152 100644 --- a/src/Twino.Ioc/obj/Release/netcoreapp3.0/Twino.Ioc.AssemblyInfo.cs +++ b/src/Twino.Ioc/obj/Release/netcoreapp3.0/Twino.Ioc.AssemblyInfo.cs @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -13,11 +14,11 @@ [assembly: System.Reflection.AssemblyCompanyAttribute("Mehmet Helvacıköylü")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyDescriptionAttribute("Twino IOC Service containers and scopes")] -[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.14")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyProductAttribute("Twino.Ioc")] [assembly: System.Reflection.AssemblyTitleAttribute("Twino.Ioc")] -[assembly: System.Reflection.AssemblyVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyVersionAttribute("2.7.14")] // Generated by the MSBuild WriteCodeFragment class. diff --git a/src/Twino.MQ.Data/Twino.MQ.Data.csproj b/src/Twino.MQ.Data/Twino.MQ.Data.csproj index 574d4e5a..118503db 100644 --- a/src/Twino.MQ.Data/Twino.MQ.Data.csproj +++ b/src/Twino.MQ.Data/Twino.MQ.Data.csproj @@ -6,9 +6,9 @@ Twino.MQ.Data Persistant queue message data library for Twino MQ twino,server,messaging,queue,mq,persistent,database,db - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.MQ/Twino.MQ.csproj b/src/Twino.MQ/Twino.MQ.csproj index a1d06a7b..7e0e587a 100644 --- a/src/Twino.MQ/Twino.MQ.csproj +++ b/src/Twino.MQ/Twino.MQ.csproj @@ -6,9 +6,9 @@ Twino.MQ Messaging Queue Server library with TMQ Protocol via Twino Server twino,server,tmq,messaging,queue,mq - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.MQ/obj/Release/netcoreapp3.0/Twino.MQ.AssemblyInfo.cs b/src/Twino.MQ/obj/Release/netcoreapp3.0/Twino.MQ.AssemblyInfo.cs index 28f942b1..94764120 100644 --- a/src/Twino.MQ/obj/Release/netcoreapp3.0/Twino.MQ.AssemblyInfo.cs +++ b/src/Twino.MQ/obj/Release/netcoreapp3.0/Twino.MQ.AssemblyInfo.cs @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -13,11 +14,11 @@ [assembly: System.Reflection.AssemblyCompanyAttribute("Mehmet Helvacıköylü")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyDescriptionAttribute("Messaging Queue Server library with TMQ Protocol via Twino Server")] -[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.14")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyProductAttribute("Twino.MQ")] [assembly: System.Reflection.AssemblyTitleAttribute("Twino.MQ")] -[assembly: System.Reflection.AssemblyVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyVersionAttribute("2.7.14")] // Generated by the MSBuild WriteCodeFragment class. diff --git a/src/Twino.Mvc.Auth.Jwt/Twino.Mvc.Auth.Jwt.csproj b/src/Twino.Mvc.Auth.Jwt/Twino.Mvc.Auth.Jwt.csproj index 4f1dbc14..7bb84559 100644 --- a/src/Twino.Mvc.Auth.Jwt/Twino.Mvc.Auth.Jwt.csproj +++ b/src/Twino.Mvc.Auth.Jwt/Twino.Mvc.Auth.Jwt.csproj @@ -6,9 +6,9 @@ Twino.Mvc.Auth.Jwt JSON Web Token Authentication and Authorization library for Twino MVC twino,http,mvc,jwt,token,authentication,authorization - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Mvc.Auth.Jwt/obj/Release/netcoreapp3.0/Twino.Mvc.Auth.Jwt.AssemblyInfo.cs b/src/Twino.Mvc.Auth.Jwt/obj/Release/netcoreapp3.0/Twino.Mvc.Auth.Jwt.AssemblyInfo.cs index 09a235a5..4b8658eb 100644 --- a/src/Twino.Mvc.Auth.Jwt/obj/Release/netcoreapp3.0/Twino.Mvc.Auth.Jwt.AssemblyInfo.cs +++ b/src/Twino.Mvc.Auth.Jwt/obj/Release/netcoreapp3.0/Twino.Mvc.Auth.Jwt.AssemblyInfo.cs @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -13,11 +14,11 @@ [assembly: System.Reflection.AssemblyCompanyAttribute("Mehmet Helvacıköylü")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyDescriptionAttribute("JSON Web Token Authentication and Authorization library for Twino MVC")] -[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.14")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyProductAttribute("Twino.Mvc.Auth.Jwt")] [assembly: System.Reflection.AssemblyTitleAttribute("Twino.Mvc.Auth.Jwt")] -[assembly: System.Reflection.AssemblyVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyVersionAttribute("2.7.14")] // Generated by the MSBuild WriteCodeFragment class. diff --git a/src/Twino.Mvc/Controllers/ActionParameter.cs b/src/Twino.Mvc/Controllers/ActionParameter.cs index 5a6d7945..04f1bf20 100644 --- a/src/Twino.Mvc/Controllers/ActionParameter.cs +++ b/src/Twino.Mvc/Controllers/ActionParameter.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Reflection; namespace Twino.Mvc.Controllers { @@ -84,5 +86,15 @@ public class ActionParameter /// Usually true when the type is int?, short?, etc. /// public bool Nullable { get; set; } + + /// + /// If true, property is a class + /// + public bool IsClass { get; set; } + + /// + /// If parameter is a class, property info list of that class. otherwise, null. + /// + public Dictionary ClassProperties { get; } = new Dictionary(StringComparer.InvariantCultureIgnoreCase); } } diff --git a/src/Twino.Mvc/MvcConnectionHandler.cs b/src/Twino.Mvc/MvcConnectionHandler.cs index 1a155bda..9b97a343 100644 --- a/src/Twino.Mvc/MvcConnectionHandler.cs +++ b/src/Twino.Mvc/MvcConnectionHandler.cs @@ -52,7 +52,7 @@ public MvcConnectionHandler(TwinoMvc mvc, MvcAppBuilder app) /// public async Task Connected(ITwinoServer server, IConnectionInfo connection, ConnectionData data) { - return await Task.FromResult((SocketBase)null); + return await Task.FromResult((SocketBase) null); } /// @@ -157,13 +157,13 @@ private async Task RequestMvc(ITwinoServer server, HttpRequest request, HttpResp user = Mvc.ClaimsPrincipalValidator.Get(request); FilterContext context = new FilterContext - { - Server = server, - Request = request, - Response = response, - Result = null, - User = user - }; + { + Server = server, + Request = request, + Response = response, + Result = null, + User = user + }; if (!CheckControllerAuthority(match, context, response)) return; @@ -185,11 +185,11 @@ private async Task RequestMvc(ITwinoServer server, HttpRequest request, HttpResp //fill action descriptor ActionDescriptor descriptor = new ActionDescriptor - { - Controller = controller, - Action = match.Route.ActionType, - Parameters = FillParameters(request, match) - }; + { + Controller = controller, + Action = match.Route.ActionType, + Parameters = FillParameters(request, match) + }; if (!CheckActionAuthority(match, context, response, descriptor)) return; @@ -211,7 +211,7 @@ private async Task ExecuteAction(RouteMatch match, FilterContext context, TwinoC { if (match.Route.IsAsyncMethod) { - Task task = (Task)match.Route.ActionType.Invoke(controller, descriptor.Parameters.Select(x => x.Value).ToArray()); + Task task = (Task) match.Route.ActionType.Invoke(controller, descriptor.Parameters.Select(x => x.Value).ToArray()); await task; await CompleteActionExecution(match, context, response, controller, descriptor, task.Result); } @@ -222,7 +222,7 @@ private async Task ExecuteAction(RouteMatch match, FilterContext context, TwinoC { try { - IActionResult ar = (IActionResult)match.Route.ActionType.Invoke(controller, descriptor.Parameters.Select(x => x.Value).ToArray()); + IActionResult ar = (IActionResult) match.Route.ActionType.Invoke(controller, descriptor.Parameters.Select(x => x.Value).ToArray()); await CompleteActionExecution(match, context, response, controller, descriptor, ar); source.SetResult(true); } @@ -279,91 +279,108 @@ public void WriteResponse(HttpResponse response, IActionResult result) /// /// Creates parameter list and sets values for the specified request to the specified route. /// - private static List FillParameters(HttpRequest request, RouteMatch route) + internal static List FillParameters(HttpRequest request, RouteMatch route) { List values = new List(); foreach (ActionParameter ap in route.Route.Parameters) { - object value = null; + ParameterValue paramValue = new ParameterValue + { + Name = ap.ParameterName, + Type = ap.ParameterType, + Source = ap.Source + }; //by source find the value of the parameter and set it to "value" local variable switch (ap.Source) { case ParameterSource.None: case ParameterSource.Route: - value = route.Values[ap.FromName]; + paramValue.Value = ChangeType(route.Values[ap.FromName], ap.ParameterType, ap.Nullable); break; case ParameterSource.Body: + { + string content = Encoding.UTF8.GetString(request.ContentStream.ToArray()); + if (ap.FromName == "json") + paramValue.Value = Newtonsoft.Json.JsonConvert.DeserializeObject(content, ap.ParameterType); + else if (ap.FromName == "xml") { - string content = Encoding.UTF8.GetString(request.ContentStream.ToArray()); - if (ap.FromName == "json") - value = Newtonsoft.Json.JsonConvert.DeserializeObject(content, ap.ParameterType); - else if (ap.FromName == "xml") + using MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(content)); + XmlSerializer serializer = new XmlSerializer(ap.ParameterType); + paramValue.Value = serializer.Deserialize(ms); + } + + break; + } + + case ParameterSource.Form: + if (ap.IsClass) + { + object obj = Activator.CreateInstance(ap.ParameterType); + string start = $"{ap.FromName}."; + var props = request.Form.Where(x => x.Key.StartsWith(start, StringComparison.InvariantCultureIgnoreCase)); + foreach (var kv in props) { - using MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(content)); - XmlSerializer serializer = new XmlSerializer(ap.ParameterType); - value = serializer.Deserialize(ms); + string propName = kv.Key.Substring(start.Length); + PropertyInfo propInfo; + ap.ClassProperties.TryGetValue(propName, out propInfo); + if (propInfo != null) + propInfo.SetValue(obj, ChangeType(kv.Value, propInfo.PropertyType, Nullable.GetUnderlyingType(propInfo.PropertyType) != null)); } - break; + paramValue.Value = obj; } + else if (request.Form.ContainsKey(ap.FromName)) + paramValue.Value = ChangeType(request.Form[ap.FromName], ap.ParameterType, ap.Nullable); - case ParameterSource.Form: - if (request.Form.ContainsKey(ap.FromName)) - value = request.Form[ap.FromName]; break; case ParameterSource.QueryString: if (request.QueryString.ContainsKey(ap.FromName)) - value = request.QueryString[ap.FromName]; + paramValue.Value = ChangeType(request.QueryString[ap.FromName], ap.ParameterType, ap.Nullable); break; case ParameterSource.Header: if (request.Headers.ContainsKey(ap.FromName)) - value = request.Headers[ap.FromName]; + paramValue.Value = ChangeType(request.Headers[ap.FromName], ap.ParameterType, ap.Nullable); break; } - //the value must be cast to the specified parameter type. - //object boxing may be misleading. - //when the parameter type of the method is integer, value could be boxed "3" string. - object casted; + //return value + values.Add(paramValue); + } - //if the value is null, parameter may be missing - if (value == null) - casted = null; + return values; + } - //if the value and parameter types same, do nothing - else if (value.GetType() == ap.ParameterType) - casted = value; + /// + /// Converts string value to action parameter type + /// + private static object ChangeType(object value, Type type, bool nullable) + { + //if the value is null, parameter may be missing + if (value == null) + return null; - //need casting. parameter and value types are different - else - { - //for nullable types, we need extra check (because we need to cast underlying type) - if (ap.Nullable) - { - Type nullable = Nullable.GetUnderlyingType(ap.ParameterType); - casted = Convert.ChangeType(value, nullable); - } + //if the value and parameter types same, do nothing + if (value.GetType() == type) + return value; - //directly cast - else - casted = Convert.ChangeType(value, ap.ParameterType); - } + //need casting. parameter and value types are different - //return value - values.Add(new ParameterValue - { - Name = ap.ParameterName, - Type = ap.ParameterType, - Source = ap.Source, - Value = casted - }); + //for nullable types, we need extra check (because we need to cast underlying type) + if (nullable) + { + Type utype = Nullable.GetUnderlyingType(type); + return Convert.ChangeType(value, utype); } - return values; + if (type.IsEnum) + return Enum.Parse(type, value.ToString()); + + //directly cast + return Convert.ChangeType(value, type); } #endregion @@ -378,7 +395,7 @@ private bool CheckControllerAuthority(RouteMatch match, FilterContext context, H if (!match.Route.HasControllerAuthorizeFilter) return true; - AuthorizeAttribute filter = (AuthorizeAttribute)match.Route.ControllerType.GetCustomAttribute(typeof(AuthorizeAttribute)); + AuthorizeAttribute filter = (AuthorizeAttribute) match.Route.ControllerType.GetCustomAttribute(typeof(AuthorizeAttribute)); if (filter != null) { filter.VerifyAuthority(Mvc, null, context); @@ -401,7 +418,7 @@ private async Task ExecuteBeforeControllerFilters(RouteMatch match, Filter return true; //find controller filters - IBeforeControllerFilter[] filters = (IBeforeControllerFilter[])match.Route.ControllerType.GetCustomAttributes(typeof(IBeforeControllerFilter), true); + IBeforeControllerFilter[] filters = (IBeforeControllerFilter[]) match.Route.ControllerType.GetCustomAttributes(typeof(IBeforeControllerFilter), true); //call BeforeCreated methods of controller attributes return await CallFilters(response, context, filters, async filter => await filter.OnBefore(context)); @@ -416,7 +433,7 @@ private async Task ExecuteAfterControllerFilters(RouteMatch match, FilterC return true; //find controller filters - IAfterControllerFilter[] filters = (IAfterControllerFilter[])match.Route.ControllerType.GetCustomAttributes(typeof(IAfterControllerFilter), true); + IAfterControllerFilter[] filters = (IAfterControllerFilter[]) match.Route.ControllerType.GetCustomAttributes(typeof(IAfterControllerFilter), true); //call AfterCreated methods of controller attributes return await CallFilters(response, context, filters, async filter => await filter.OnAfter(controller, context)); @@ -431,7 +448,7 @@ private bool CheckActionAuthority(RouteMatch match, FilterContext context, HttpR return true; //check action authorize attribute - AuthorizeAttribute filter = (AuthorizeAttribute)match.Route.ActionType.GetCustomAttribute(typeof(AuthorizeAttribute)); + AuthorizeAttribute filter = (AuthorizeAttribute) match.Route.ActionType.GetCustomAttribute(typeof(AuthorizeAttribute)); if (filter != null) { filter.VerifyAuthority(Mvc, descriptor, context); @@ -453,7 +470,7 @@ private async Task CheckActionExecutingFilters(RouteMatch match, FilterCon if (match.Route.HasControllerExecutingFilter) { //find controller filters - IActionExecutingFilter[] filters = (IActionExecutingFilter[])match.Route.ControllerType.GetCustomAttributes(typeof(IActionExecutingFilter), true); + IActionExecutingFilter[] filters = (IActionExecutingFilter[]) match.Route.ControllerType.GetCustomAttributes(typeof(IActionExecutingFilter), true); //call BeforeCreated methods of controller attributes bool resume = await CallFilters(response, context, filters, async filter => await filter.OnExecuting(controller, descriptor, context)); @@ -464,7 +481,7 @@ private async Task CheckActionExecutingFilters(RouteMatch match, FilterCon if (match.Route.HasActionExecutingFilter) { //find controller filters - IActionExecutingFilter[] filters = (IActionExecutingFilter[])match.Route.ActionType.GetCustomAttributes(typeof(IActionExecutingFilter), true); + IActionExecutingFilter[] filters = (IActionExecutingFilter[]) match.Route.ActionType.GetCustomAttributes(typeof(IActionExecutingFilter), true); //call BeforeCreated methods of controller attributes bool resume = await CallFilters(response, context, filters, async filter => await filter.OnExecuting(controller, descriptor, context)); @@ -493,7 +510,7 @@ private async Task CheckActionExecutingFilters(RouteMatch match, FilterCon if (match.Route.HasActionExecutedFilter) { //find controller filters - IActionExecutedFilter[] filters = (IActionExecutedFilter[])match.Route.ActionType.GetCustomAttributes(typeof(IActionExecutedFilter), true); + IActionExecutedFilter[] filters = (IActionExecutedFilter[]) match.Route.ActionType.GetCustomAttributes(typeof(IActionExecutedFilter), true); //call AfterCreated methods of controller attributes foreach (IActionExecutedFilter filter in filters) @@ -503,7 +520,7 @@ private async Task CheckActionExecutingFilters(RouteMatch match, FilterCon if (match.Route.HasControllerExecutedFilter) { //find controller filters - IActionExecutedFilter[] filters = (IActionExecutedFilter[])match.Route.ControllerType.GetCustomAttributes(typeof(IActionExecutedFilter), true); + IActionExecutedFilter[] filters = (IActionExecutedFilter[]) match.Route.ControllerType.GetCustomAttributes(typeof(IActionExecutedFilter), true); //call AfterCreated methods of controller attributes foreach (IActionExecutedFilter filter in filters) diff --git a/src/Twino.Mvc/Routing/RouteBuilder.cs b/src/Twino.Mvc/Routing/RouteBuilder.cs index 1666d721..6ceb3e19 100644 --- a/src/Twino.Mvc/Routing/RouteBuilder.cs +++ b/src/Twino.Mvc/Routing/RouteBuilder.cs @@ -73,14 +73,14 @@ public IEnumerable BuildRoutes(Type controllerType) if (i == path.Count - 1) { leaf.Route = new Route - { - ActionType = method, - ControllerType = controllerType, - Method = info.Method, - Path = path.ToArray(), - Parameters = BuildParameters(method), - IsAsyncMethod = (AsyncStateMachineAttribute)method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null - }; + { + ActionType = method, + ControllerType = controllerType, + Method = info.Method, + Path = path.ToArray(), + Parameters = BuildParameters(method), + IsAsyncMethod = (AsyncStateMachineAttribute) method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null + }; } } @@ -93,6 +93,37 @@ public IEnumerable BuildRoutes(Type controllerType) return routes; } + /// + /// Sorts all route leaves recursively + /// + internal void SortChildren(RouteLeaf leaf) + { + if (leaf.Children.Count == 0) + return; + + SortRoutes(leaf.Children); + + foreach (RouteLeaf child in leaf.Children) + SortChildren(child); + } + + internal void SortRoutes(List leaves) + { + if (leaves.Count < 2) + return; + + leaves.Sort((a, b) => + { + if (string.IsNullOrEmpty(a.Path.Value)) + return 1; + + if (string.IsNullOrEmpty(b.Path.Value)) + return -1; + + return 0; + }); + } + /// /// Searches method attributes and applies existing attributes to route /// @@ -214,11 +245,11 @@ private List FindActionRoute(MethodInfo method) string pattern = attr.Pattern ?? ""; RouteInfo route = new RouteInfo - { - Method = attr.Method, - Pattern = pattern, - Path = pattern.Split('/', StringSplitOptions.RemoveEmptyEntries) - }; + { + Method = attr.Method, + Pattern = pattern, + Path = pattern.Split('/', StringSplitOptions.RemoveEmptyEntries) + }; routes.Add(route); } @@ -236,10 +267,10 @@ private List GetRoutePath(MethodInfo action, string fullpath) if (string.IsNullOrEmpty(fullpath)) { result.Add(new RoutePath - { - Type = RouteType.Text, - Value = "" - }); + { + Type = RouteType.Text, + Value = "" + }); return result; } @@ -308,7 +339,7 @@ private ActionParameter[] BuildParameters(MethodInfo method) if (attr != null) { if (attr.Source == ParameterSource.Body) - from = ((FromBodyAttribute)attr).Type.ToString().ToLower(); + from = ((FromBodyAttribute) attr).Type.ToString().ToLower(); else from = string.IsNullOrEmpty(attr.Name) ? parameter.Name : attr.Name; } @@ -316,14 +347,22 @@ private ActionParameter[] BuildParameters(MethodInfo method) from = parameter.Name; ActionParameter item = new ActionParameter + { + ParameterType = parameter.ParameterType, + ParameterName = parameter.Name, + FromName = from, + Index = i, + Source = attr != null ? attr.Source : ParameterSource.None, + Nullable = Nullable.GetUnderlyingType(parameter.ParameterType) != null, + IsClass = parameter.ParameterType.IsClass && parameter.ParameterType != typeof(string) + }; + + if (item.IsClass) { - ParameterType = parameter.ParameterType, - ParameterName = parameter.Name, - FromName = from, - Index = i, - Source = attr != null ? attr.Source : ParameterSource.None, - Nullable = Nullable.GetUnderlyingType(parameter.ParameterType) != null - }; + PropertyInfo[] properties = parameter.ParameterType.GetProperties(); + foreach (PropertyInfo property in properties) + item.ClassProperties.Add(property.Name, property); + } result[i] = item; } diff --git a/src/Twino.Mvc/Routing/RouteFinder.cs b/src/Twino.Mvc/Routing/RouteFinder.cs index cf574f77..2bf888ca 100644 --- a/src/Twino.Mvc/Routing/RouteFinder.cs +++ b/src/Twino.Mvc/Routing/RouteFinder.cs @@ -58,7 +58,24 @@ private RouteLeaf FindRouteInLeaf(RouteLeaf leaf, string method, string[] parts, //for text parts, it should match if (leaf.Path.Type == RouteType.Text) { - bool matched = leaf.Path.Value.Equals(parts[index], StringComparison.InvariantCultureIgnoreCase); + if (string.IsNullOrEmpty(leaf.Path.Value)) + { + if (leaf.Route != null && leaf.Route.Method.Equals(method, StringComparison.InvariantCultureIgnoreCase)) + return leaf; + + foreach (RouteLeaf child in leaf.Children) + { + RouteLeaf rl = FindRouteInLeaf(child, method, parts, index); + if (rl != null) + return rl; + } + } + + bool matched = false; + + if (index < parts.Length) + matched = leaf.Path.Value.Equals(parts[index], StringComparison.InvariantCultureIgnoreCase); + if (!matched) return null; } @@ -106,9 +123,6 @@ private RouteLeaf FindRouteInLeaf(RouteLeaf leaf, string method, string[] parts, } } - if (parts.Length < index + 2) - return null; - int next = index + 1; foreach (RouteLeaf child in leaf.Children) { @@ -128,7 +142,7 @@ public RouteMatch Find(IEnumerable routes, HttpRequest request) //split path to route parts string[] parts = request.Path.Split('/', StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) - parts = new[] { "" }; + parts = new[] {""}; RouteLeaf route = null; foreach (RouteLeaf leaf in routes) @@ -167,7 +181,8 @@ public RouteMatch Find(IEnumerable routes, HttpRequest request) match.Values.Add(path.Value, parts[route.Index]); route = route.Parent; - } while (route != null); + } + while (route != null); return match; } diff --git a/src/Twino.Mvc/Routing/RouteLeaf.cs b/src/Twino.Mvc/Routing/RouteLeaf.cs index 17cad8fe..e419763f 100644 --- a/src/Twino.Mvc/Routing/RouteLeaf.cs +++ b/src/Twino.Mvc/Routing/RouteLeaf.cs @@ -48,7 +48,7 @@ public RouteLeaf(RoutePath path, RouteLeaf parent) Path = path; Parent = parent; - if (parent != null) + if (parent != null && !string.IsNullOrEmpty(parent.Path.Value)) Index = parent.Index + 1; } diff --git a/src/Twino.Mvc/Twino.Mvc.csproj b/src/Twino.Mvc/Twino.Mvc.csproj index 7cabaa61..15fe3396 100644 --- a/src/Twino.Mvc/Twino.Mvc.csproj +++ b/src/Twino.Mvc/Twino.Mvc.csproj @@ -6,9 +6,9 @@ Twino.Mvc MVC Library for Twino Http Server twino,http,server,mvc - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Mvc/TwinoMvc.cs b/src/Twino.Mvc/TwinoMvc.cs index 0aefd558..c08bfe48 100644 --- a/src/Twino.Mvc/TwinoMvc.cs +++ b/src/Twino.Mvc/TwinoMvc.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Net; using System.Reflection; +using System.Runtime.CompilerServices; using Twino.Core; using Twino.Ioc; using Twino.Mvc.Auth; @@ -12,6 +13,8 @@ using Twino.Mvc.Results; using Twino.Mvc.Routing; +[assembly:InternalsVisibleTo("Test.Mvc")] + namespace Twino.Mvc { /// @@ -169,6 +172,8 @@ public void CreateRoutes(Assembly assembly = null) .Where(type => interfaceType.IsAssignableFrom(type)) .ToList(); + List leaves = new List(); + foreach (Type type in types) { if (type.IsInterface) @@ -177,10 +182,15 @@ public void CreateRoutes(Assembly assembly = null) if (type.IsAssignableFrom(typeof(TwinoController)) && typeof(TwinoController).IsAssignableFrom(type)) continue; - IEnumerable routes = builder.BuildRoutes(type); - foreach (RouteLeaf route in routes) - Routes.Add(route); + leaves.AddRange(builder.BuildRoutes(type)); } + + foreach (RouteLeaf root in leaves) + builder.SortChildren(root); + + builder.SortRoutes(leaves); + foreach (RouteLeaf route in leaves) + Routes.Add(route); } /// diff --git a/src/Twino.Protocols.Http/Forms/EncodedFormDataReader.cs b/src/Twino.Protocols.Http/Forms/EncodedFormDataReader.cs index 01e06f2e..6cdd42ef 100644 --- a/src/Twino.Protocols.Http/Forms/EncodedFormDataReader.cs +++ b/src/Twino.Protocols.Http/Forms/EncodedFormDataReader.cs @@ -40,7 +40,7 @@ public static class EncodedFormDataReader continue; string key = key_value[0]; - string value = System.Net.WebUtility.HtmlDecode(key_value[1]); + string value = System.Net.WebUtility.UrlDecode(key_value[1]); if (items.ContainsKey(key)) items[key] = "," + value; diff --git a/src/Twino.Protocols.Http/HttpRequest.cs b/src/Twino.Protocols.Http/HttpRequest.cs index 98c347ff..4d37d832 100644 --- a/src/Twino.Protocols.Http/HttpRequest.cs +++ b/src/Twino.Protocols.Http/HttpRequest.cs @@ -4,6 +4,7 @@ using System.Runtime.CompilerServices; using Twino.Protocols.Http.Forms; +[assembly: InternalsVisibleTo("Test.Mvc")] [assembly: InternalsVisibleTo("Twino.Server")] [assembly: InternalsVisibleTo("Twino.Client.WebSocket")] diff --git a/src/Twino.Protocols.Http/Twino.Protocols.Http.csproj b/src/Twino.Protocols.Http/Twino.Protocols.Http.csproj index 7fc410a9..cf6b4f31 100644 --- a/src/Twino.Protocols.Http/Twino.Protocols.Http.csproj +++ b/src/Twino.Protocols.Http/Twino.Protocols.Http.csproj @@ -6,9 +6,9 @@ Twino.Protocols.Http Twino Http Protocol library and server extension for Twino Server twino,tcp,server,http,protocol - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Protocols.Http/obj/Release/netcoreapp3.0/Twino.Protocols.Http.AssemblyInfo.cs b/src/Twino.Protocols.Http/obj/Release/netcoreapp3.0/Twino.Protocols.Http.AssemblyInfo.cs index 67183627..647857c0 100644 --- a/src/Twino.Protocols.Http/obj/Release/netcoreapp3.0/Twino.Protocols.Http.AssemblyInfo.cs +++ b/src/Twino.Protocols.Http/obj/Release/netcoreapp3.0/Twino.Protocols.Http.AssemblyInfo.cs @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -13,11 +14,11 @@ [assembly: System.Reflection.AssemblyCompanyAttribute("Mehmet Helvacıköylü")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyDescriptionAttribute("Twino Http Protocol library and server extension for Twino Server")] -[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.14")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyProductAttribute("Twino.Protocols.Http")] [assembly: System.Reflection.AssemblyTitleAttribute("Twino.Protocols.Http")] -[assembly: System.Reflection.AssemblyVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyVersionAttribute("2.7.14")] // Generated by the MSBuild WriteCodeFragment class. diff --git a/src/Twino.Protocols.TMQ/Twino.Protocols.TMQ.csproj b/src/Twino.Protocols.TMQ/Twino.Protocols.TMQ.csproj index 86440a28..281a4881 100644 --- a/src/Twino.Protocols.TMQ/Twino.Protocols.TMQ.csproj +++ b/src/Twino.Protocols.TMQ/Twino.Protocols.TMQ.csproj @@ -6,9 +6,9 @@ Twino.Protocols.TMQ Twino Messaging Queue (TMQ) Protocol library and server extension for Twino Server twino,tcp,server,http,messaging,queue,tmq,mq,protocol - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Protocols.WebSocket/Twino.Protocols.WebSocket.csproj b/src/Twino.Protocols.WebSocket/Twino.Protocols.WebSocket.csproj index 3d2b1fb5..92991df0 100644 --- a/src/Twino.Protocols.WebSocket/Twino.Protocols.WebSocket.csproj +++ b/src/Twino.Protocols.WebSocket/Twino.Protocols.WebSocket.csproj @@ -6,9 +6,9 @@ Twino.Protocols.WebSocket WebSocket Protocol library and server extension for Twino Server twino,tcp,server,http,websocket,protocol,ws - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.Protocols.WebSocket/obj/Release/netcoreapp3.0/Twino.Protocols.WebSocket.AssemblyInfo.cs b/src/Twino.Protocols.WebSocket/obj/Release/netcoreapp3.0/Twino.Protocols.WebSocket.AssemblyInfo.cs index cf227917..77191714 100644 --- a/src/Twino.Protocols.WebSocket/obj/Release/netcoreapp3.0/Twino.Protocols.WebSocket.AssemblyInfo.cs +++ b/src/Twino.Protocols.WebSocket/obj/Release/netcoreapp3.0/Twino.Protocols.WebSocket.AssemblyInfo.cs @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -13,11 +14,11 @@ [assembly: System.Reflection.AssemblyCompanyAttribute("Mehmet Helvacıköylü")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyDescriptionAttribute("WebSocket Protocol library and server extension for Twino Server")] -[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.14")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyProductAttribute("Twino.Protocols.WebSocket")] [assembly: System.Reflection.AssemblyTitleAttribute("Twino.Protocols.WebSocket")] -[assembly: System.Reflection.AssemblyVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyVersionAttribute("2.7.14")] // Generated by the MSBuild WriteCodeFragment class. diff --git a/src/Twino.SerializableModel/Twino.SerializableModel.csproj b/src/Twino.SerializableModel/Twino.SerializableModel.csproj index 3325037e..294f79c9 100644 --- a/src/Twino.SerializableModel/Twino.SerializableModel.csproj +++ b/src/Twino.SerializableModel/Twino.SerializableModel.csproj @@ -6,9 +6,9 @@ Twino.SerializableModel Twino Serializable Model library for object based communication with text-based protocols twino,tcp,server,http,websocket,serilizable,model - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino diff --git a/src/Twino.SerializableModel/obj/Release/netcoreapp3.0/Twino.SerializableModel.AssemblyInfo.cs b/src/Twino.SerializableModel/obj/Release/netcoreapp3.0/Twino.SerializableModel.AssemblyInfo.cs index 0159f167..47f7afa1 100644 --- a/src/Twino.SerializableModel/obj/Release/netcoreapp3.0/Twino.SerializableModel.AssemblyInfo.cs +++ b/src/Twino.SerializableModel/obj/Release/netcoreapp3.0/Twino.SerializableModel.AssemblyInfo.cs @@ -1,6 +1,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. +// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -14,11 +15,11 @@ [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyDescriptionAttribute("Twino Serializable Model library for object based communication with text-based p" + "rotocols")] -[assembly: System.Reflection.AssemblyFileVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("27.14")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyProductAttribute("Twino.SerializableModel")] [assembly: System.Reflection.AssemblyTitleAttribute("Twino.SerializableModel")] -[assembly: System.Reflection.AssemblyVersionAttribute("2.7.10")] +[assembly: System.Reflection.AssemblyVersionAttribute("27.14")] // Generated by the MSBuild WriteCodeFragment class. diff --git a/src/Twino.Server/Twino.Server.csproj b/src/Twino.Server/Twino.Server.csproj index fda7c063..352482ed 100644 --- a/src/Twino.Server/Twino.Server.csproj +++ b/src/Twino.Server/Twino.Server.csproj @@ -6,9 +6,9 @@ Twino.Server Twino TCP Socket Server twino,tcp,socket,server,http,websocket,tmq,mq - 2.7.12 - 2.7.12 - 2.7.12 + 2.7.14 + 2.7.14 + 2.7.14 true Mehmet Helvacıköylü https://github.com/mhelvacikoylu/twino