├── source ├── .nuget │ ├── NuGet.exe │ └── NuGet.Config ├── ServiceProxy.Zmq_old │ ├── libzmq.dll │ ├── packages.config │ ├── README.md │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Extensions.cs │ ├── ZmqResponse.cs │ └── ZmqRequest.cs ├── ServiceProxy.Zmq_old.Tests │ ├── libzmq.dll │ ├── packages.config │ └── Properties │ │ └── AssemblyInfo.cs ├── ServiceProxy.Redis.Tests │ ├── redis-server.lnk │ ├── App.config │ ├── packages.config │ ├── Properties │ │ └── AssemblyInfo.cs │ └── ServiceProxy.Redis.Tests.csproj ├── ServiceProxy.Zmq │ ├── packages.config │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── README.md │ ├── ZmqResponse.cs │ ├── ZmqRequest.cs │ ├── Extensions.cs │ └── ServiceProxy.Zmq.csproj ├── ServiceProxy │ ├── packages.config │ ├── IDependencyResolver.cs │ ├── IService.cs │ ├── IClient.cs │ ├── IServiceClientFactory.cs │ ├── IServiceFactory.cs │ ├── RequestData.cs │ ├── ResponseData.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ServiceFactory.cs │ ├── Internal │ │ ├── TimeoutClient.cs │ │ ├── Service.cs │ │ ├── ServiceClientInterceptor.cs │ │ └── OperationInvokers.cs │ ├── ServiceClientFactory.cs │ ├── ServiceProxy.csproj │ └── README.md ├── ServiceProxy.Redis │ ├── packages.config │ ├── RedisConnection.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Extensions.cs │ ├── README.md │ ├── RedisResponse.cs │ ├── RedisRequest.cs │ ├── RedisServer.cs │ ├── ServiceProxy.Redis.csproj │ └── RedisClient.cs ├── ServiceProxy.Tests │ ├── packages.config │ ├── Stubs │ │ ├── DependencyResolver.cs │ │ └── SimpleClient.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── ClientAndServerTests.cs │ ├── ClientTests.cs │ ├── ServiceTests.cs │ └── ServiceProxy.Tests.csproj └── ServiceProxy.Zmq.Tests │ ├── packages.config │ └── Properties │ └── AssemblyInfo.cs ├── examples ├── MyApp │ ├── .nuget │ │ ├── NuGet.exe │ │ └── NuGet.Config │ ├── MyApp.WebAPI │ │ ├── favicon.ico │ │ ├── Global.asax │ │ ├── SwaggerUI │ │ │ ├── lib │ │ │ │ ├── .DS_Store │ │ │ │ ├── jquery.slideto.min.js │ │ │ │ ├── jquery.wiggle.min.js │ │ │ │ └── jquery.ba-bbq.min.js │ │ │ ├── images │ │ │ │ ├── wordnik_api.png │ │ │ │ └── pet_store_api.png │ │ │ └── index.html │ │ ├── App_Start │ │ │ ├── FilterConfig.cs │ │ │ ├── RouteConfig.cs │ │ │ ├── ServiceProxyAutofacModule.cs │ │ │ ├── AutofacConfig.cs │ │ │ ├── WebApiConfig.cs │ │ │ └── SwaggerNet.cs │ │ ├── Global.asax.cs │ │ ├── Controllers │ │ │ ├── CatalogController.cs │ │ │ ├── AsyncCatalogController.cs │ │ │ └── FooController.cs │ │ ├── Web.Debug.config │ │ ├── Web.Release.config │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── packages.config │ │ └── Web.config │ ├── MyApp.Broker │ │ ├── App.config │ │ ├── packages.config │ │ ├── Program.cs │ │ └── Properties │ │ │ └── AssemblyInfo.cs │ ├── MyApp.Worker │ │ ├── App.config │ │ ├── packages.config │ │ ├── LogInterceptor.cs │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ └── Program.cs │ ├── MyApp.Services │ │ ├── IFooService.cs │ │ ├── ICatalogService.cs │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── Model.cs │ │ └── MyApp.Services.csproj │ ├── MyApp.Services.InMemory │ │ ├── Properties │ │ │ └── AssemblyInfo.cs │ │ ├── FooService.cs │ │ ├── MyApp.Services.InMemory.csproj │ │ └── CatalogService.cs │ └── MyApp.sln └── Redis │ ├── .nuget │ ├── NuGet.exe │ └── NuGet.Config │ ├── Client │ ├── App.config │ ├── packages.config │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Program.cs │ └── Client.csproj │ ├── Server │ ├── App.config │ ├── packages.config │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── FooService.cs │ └── Server.csproj │ ├── ServiceContracts │ ├── Foo.cs │ ├── IFooService.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ └── ServiceContracts.csproj │ └── RedisSamples.sln ├── nuget ├── ServiceProxy │ ├── pack.cmd │ └── ServiceProxy.nuspec ├── ServiceProxy.Zmq │ ├── pack.cmd │ └── ServiceProxy.Zmq.nuspec ├── ServiceProxy.Redis │ ├── pack.cmd │ └── ServiceProxy.Redis.nuspec ├── ServiceProxy.Zmq_old │ ├── pack.cmd │ └── ServiceProxy.Zmq.nuspec └── pack.cmd ├── CHANGELOG.md ├── LICENSE ├── .gitignore ├── .gitattributes └── README.md /source/.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/source/.nuget/NuGet.exe -------------------------------------------------------------------------------- /examples/MyApp/.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/examples/MyApp/.nuget/NuGet.exe -------------------------------------------------------------------------------- /examples/Redis/.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/examples/Redis/.nuget/NuGet.exe -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old/libzmq.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/source/ServiceProxy.Zmq_old/libzmq.dll -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/examples/MyApp/MyApp.WebAPI/favicon.ico -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="MyApp.WebAPI.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old.Tests/libzmq.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/source/ServiceProxy.Zmq_old.Tests/libzmq.dll -------------------------------------------------------------------------------- /source/ServiceProxy.Redis.Tests/redis-server.lnk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/source/ServiceProxy.Redis.Tests/redis-server.lnk -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/SwaggerUI/lib/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/examples/MyApp/MyApp.WebAPI/SwaggerUI/lib/.DS_Store -------------------------------------------------------------------------------- /source/ServiceProxy.Redis.Tests/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/SwaggerUI/images/wordnik_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/examples/MyApp/MyApp.WebAPI/SwaggerUI/images/wordnik_api.png -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/SwaggerUI/images/pet_store_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfelicio/ServiceProxy/HEAD/examples/MyApp/MyApp.WebAPI/SwaggerUI/images/pet_store_api.png -------------------------------------------------------------------------------- /nuget/ServiceProxy/pack.cmd: -------------------------------------------------------------------------------- 1 | xcopy ..\..\source\ServiceProxy\bin\Release\ServiceProxy.dll lib\net45\ /y 2 | 3 | NuGet.exe pack ServiceProxy.nuspec -exclude *.cmd -OutputDirectory ..\ -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /source/ServiceProxy/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nuget/ServiceProxy.Zmq/pack.cmd: -------------------------------------------------------------------------------- 1 | xcopy ..\..\source\ServiceProxy.Zmq\bin\Release\ServiceProxy.Zmq.dll lib\net45\ /y 2 | 3 | NuGet.exe pack ServiceProxy.Zmq.nuspec -exclude *.cmd -OutputDirectory ..\ -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /nuget/ServiceProxy.Redis/pack.cmd: -------------------------------------------------------------------------------- 1 | xcopy ..\..\source\ServiceProxy.Redis\bin\Release\ServiceProxy.Redis.dll lib\net45\ /y 2 | 3 | NuGet.exe pack ServiceProxy.Redis.nuspec -exclude *.cmd -OutputDirectory ..\ -------------------------------------------------------------------------------- /nuget/ServiceProxy.Zmq_old/pack.cmd: -------------------------------------------------------------------------------- 1 | xcopy ..\..\source\ServiceProxy.Zmq_old\bin\Release\ServiceProxy.Zmq.dll lib\net45\ /y 2 | 3 | NuGet.exe pack ServiceProxy.Zmq.nuspec -exclude *.cmd -OutputDirectory ..\ -------------------------------------------------------------------------------- /source/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/MyApp/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/Redis/.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/Redis/Client/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/Redis/Server/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Broker/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Worker/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /nuget/pack.cmd: -------------------------------------------------------------------------------- 1 | cd ServiceProxy 2 | call pack.cmd 3 | 4 | cd .. 5 | cd ServiceProxy.Redis 6 | call pack.cmd 7 | 8 | cd.. 9 | cd ServiceProxy.Zmq 10 | call pack.cmd 11 | 12 | cd.. 13 | cd ServiceProxy.Zmq_old 14 | call pack.cmd -------------------------------------------------------------------------------- /source/ServiceProxy.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /source/ServiceProxy.Redis.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Release notes 2 | ============ 3 | 4 | ## 1.0.1 5 | 6 | * Added support for timeouts on client requests. 7 | 8 | ## 1.0.0 9 | 10 | * First public release. 11 | * Added ServiceProxy.Zmq and ServiceProxy.Redis as implementations of the IClient interface. -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old.Tests/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /source/ServiceProxy/IDependencyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy 8 | { 9 | public interface IDependencyResolver 10 | { 11 | object Resolve(Type type); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /source/ServiceProxy/IService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy 8 | { 9 | public interface IService 10 | { 11 | Task Process(RequestData requestData); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/App_Start/FilterConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Web; 2 | using System.Web.Mvc; 3 | 4 | namespace MyApp.WebAPI 5 | { 6 | public class FilterConfig 7 | { 8 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 9 | { 10 | filters.Add(new HandleErrorAttribute()); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /examples/Redis/ServiceContracts/Foo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceContracts 8 | { 9 | [Serializable] 10 | public class Foo 11 | { 12 | public int Id { get; set; } 13 | public string Name { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /source/ServiceProxy/IClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace ServiceProxy 9 | { 10 | public interface IClient 11 | { 12 | Task Request(RequestData request, CancellationToken token); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Broker/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/Redis/Client/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/Redis/Server/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/SwaggerUI/lib/jquery.slideto.min.js: -------------------------------------------------------------------------------- 1 | (function(b){b.fn.slideto=function(a){a=b.extend({slide_duration:"slow",highlight_duration:3E3,highlight:true,highlight_color:"#FFFF99"},a);return this.each(function(){obj=b(this);b("body").animate({scrollTop:obj.offset().top},a.slide_duration,function(){a.highlight&&b.ui.version&&obj.effect("highlight",{color:a.highlight_color},a.highlight_duration)})})}})(jQuery); 2 | -------------------------------------------------------------------------------- /source/ServiceProxy/IServiceClientFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy 8 | { 9 | public interface IServiceClientFactory 10 | { 11 | TService CreateServiceClient(int? timeout = null) where TService : class; 12 | object CreateServiceClient(Type serviceType, int? timeout = null); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /source/ServiceProxy/IServiceFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy 8 | { 9 | public interface IServiceFactory 10 | { 11 | IService CreateService() where TService : class; 12 | 13 | IService CreateService(string serviceName); 14 | 15 | IService CreateService(Type serviceType); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/Redis/ServiceContracts/IFooService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceContracts 8 | { 9 | public interface IFooService 10 | { 11 | Foo GetFoo(int id); 12 | Task GetFooAsync(int id); 13 | 14 | IEnumerable ListFoos(); 15 | Task> ListFoosAsync(); 16 | 17 | void UpdateFoo(Foo foo); 18 | Task UpdateFooAsync(Foo foo); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Worker/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old/README.md: -------------------------------------------------------------------------------- 1 | ServiceProxy.Zmq_old 2 | ============ 3 | 4 | ServiceProxy.Zmq_old is a scalable request/reply messaging framework built with ZeroMQ that supports service contracts using ServiceProxy. 5 | 6 | This version is as functional as the new [ServiceProxy.Zmq][serviceproxy.zmq-github] version. However it uses an old version of [clrzmq][clrzmq-github] with libzmq 2.2 7 | 8 | For reference use the new 9 | 10 | [serviceproxy.zmq-github]: https://github.com/mfelicio/ServiceProxy/tree/master/source/ServiceProxy.Zmq 11 | [clrzmq-github]: https://github.com/zeromq/clrzmq 12 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Services/IFooService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace MyApp.Services 8 | { 9 | public interface IFooService 10 | { 11 | void DoNothing(); 12 | 13 | Task AsyncOperationThatTakesTimeAndMayFail(int operationTime, bool fail); 14 | 15 | IAsyncResult BeginSum(int arg1, int arg2, AsyncCallback asyncCallback, object asyncState); 16 | int EndSum(IAsyncResult asyncResult); 17 | 18 | Catalog GetRandomCatalog(); 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /source/ServiceProxy.Tests/Stubs/DependencyResolver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy.Tests.Stubs 8 | { 9 | public class DependencyResolver : IDependencyResolver 10 | { 11 | public object Resolve(Type type) 12 | { 13 | if (type == typeof(ITestService) || type == typeof(ITestService2)) 14 | { 15 | return new TestService(); 16 | } 17 | 18 | return Activator.CreateInstance(type); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Services/ICatalogService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace MyApp.Services 8 | { 9 | public interface ICatalogService 10 | { 11 | IEnumerable GetCatalogNames(); 12 | Task> GetCatalogNamesAsync(); 13 | 14 | Catalog GetCatalog(string name); 15 | Task GetCatalogAsync(string name); 16 | 17 | ItemDetails GetItemDetails(string code); 18 | Task GetItemDetailsAsync(string code); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Worker/LogInterceptor.cs: -------------------------------------------------------------------------------- 1 | using Castle.DynamicProxy; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace MyApp.Worker 9 | { 10 | public class LogInterceptor : IInterceptor 11 | { 12 | public void Intercept(IInvocation invocation) 13 | { 14 | Console.WriteLine("Calling method {0} with parameters {1}... ", 15 | invocation.Method.Name, 16 | string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray())); 17 | 18 | invocation.Proceed(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /source/ServiceProxy/RequestData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy 8 | { 9 | [Serializable] 10 | public class RequestData 11 | { 12 | public RequestData(string service, string operation, object[] arguments) 13 | { 14 | this.Service = service; 15 | this.Operation = operation; 16 | this.Arguments = arguments; 17 | } 18 | 19 | public string Service { get; private set; } 20 | public string Operation { get; private set; } 21 | public object[] Arguments { get; private set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/App_Start/RouteConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web; 5 | using System.Web.Mvc; 6 | using System.Web.Routing; 7 | 8 | namespace MyApp.WebAPI 9 | { 10 | public class RouteConfig 11 | { 12 | public static void RegisterRoutes(RouteCollection routes) 13 | { 14 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 15 | 16 | routes.MapRoute( 17 | name: "Default", 18 | url: "{controller}/{action}/{id}", 19 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } 20 | ); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /source/ServiceProxy/ResponseData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy 8 | { 9 | [Serializable] 10 | public class ResponseData 11 | { 12 | public ResponseData(object data) 13 | { 14 | this.Data = data; 15 | this.Exception = null; 16 | } 17 | 18 | public ResponseData(Exception error) 19 | { 20 | this.Data = null; 21 | this.Exception = error; 22 | } 23 | 24 | public object Data { get; private set; } 25 | public Exception Exception { get; private set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/SwaggerUI/lib/jquery.wiggle.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | jQuery Wiggle 3 | Author: WonderGroup, Jordan Thomas 4 | URL: http://labs.wondergroup.com/demos/mini-ui/index.html 5 | License: MIT (http://en.wikipedia.org/wiki/MIT_License) 6 | */ 7 | jQuery.fn.wiggle=function(o){var d={speed:50,wiggles:3,travel:5,callback:null};var o=jQuery.extend(d,o);return this.each(function(){var cache=this;var wrap=jQuery(this).wrap('
').css("position","relative");var calls=0;for(i=1;i<=o.wiggles;i++){jQuery(this).animate({left:"-="+o.travel},o.speed).animate({left:"+="+o.travel*2},o.speed*2).animate({left:"-="+o.travel},o.speed,function(){calls++;if(jQuery(cache).parent().hasClass('wiggle-wrap')){jQuery(cache).parent().replaceWith(cache);} 8 | if(calls==o.wiggles&&jQuery.isFunction(o.callback)){o.callback();}});}});}; -------------------------------------------------------------------------------- /source/ServiceProxy.Tests/Stubs/SimpleClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace ServiceProxy.Tests.Stubs 9 | { 10 | class SimpleClient : IClient 11 | { 12 | private readonly IServiceFactory serviceFactory; 13 | 14 | public SimpleClient(IServiceFactory serviceFactory) 15 | { 16 | this.serviceFactory = serviceFactory; 17 | } 18 | 19 | public Task Request(RequestData request, CancellationToken token) 20 | { 21 | var svc = this.serviceFactory.CreateService(request.Service); 22 | var responseTask = svc.Process(request); 23 | 24 | return responseTask; 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /nuget/ServiceProxy/ServiceProxy.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ServiceProxy 5 | 1.0.1 6 | ServiceProxy 7 | Manuel Felicio 8 | Manuel Felicio 9 | http://opensource.org/licenses/mit-license.php 10 | http://github.com/mfelicio/ServiceProxy 11 | false 12 | ServiceProxy is a lightweight asynchronous service proxy that allows you to use service contracts in a request/reply manner with your favorite messaging framework. 13 | Copyright 2014 Manuel Felício 14 | messaging services proxy interceptor request reply async asynchronous 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Integration.WebApi; 3 | using MyApp.Services; 4 | using ServiceProxy; 5 | using ServiceProxy.Zmq; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Web; 10 | using System.Web.Http; 11 | using System.Web.Mvc; 12 | using System.Web.Optimization; 13 | using System.Web.Routing; 14 | 15 | namespace MyApp.WebAPI 16 | { 17 | // Note: For instructions on enabling IIS6 or IIS7 classic mode, 18 | // visit http://go.microsoft.com/?LinkId=9394801 19 | 20 | public class WebApiApplication : System.Web.HttpApplication 21 | { 22 | protected void Application_Start() 23 | { 24 | AreaRegistration.RegisterAllAreas(); 25 | 26 | WebApiConfig.Register(GlobalConfiguration.Configuration); 27 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 28 | RouteConfig.RegisterRoutes(RouteTable.Routes); 29 | 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /nuget/ServiceProxy.Zmq_old/ServiceProxy.Zmq.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ServiceProxy.Zmq 5 | 1.0.1 6 | ServiceProxy.Zmq 7 | Manuel Felicio 8 | Manuel Felicio 9 | http://opensource.org/licenses/mit-license.php 10 | http://github.com/mfelicio/ServiceProxy 11 | false 12 | ServiceProxy.Zmq is a scalable request/reply messaging framework built with ZeroMQ that supports service contracts using ServiceProxy. 13 | Copyright 2014 Manuel Felício 14 | zmq zeromq 0mq messaging services request reply proxy async asynchronous 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /nuget/ServiceProxy.Zmq/ServiceProxy.Zmq.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ServiceProxy.Zmq 5 | 1.1.0-beta 6 | ServiceProxy.Zmq 7 | Manuel Felicio 8 | Manuel Felicio 9 | http://opensource.org/licenses/mit-license.php 10 | http://github.com/mfelicio/ServiceProxy 11 | false 12 | ServiceProxy.Zmq is a scalable request/reply messaging framework built with ZeroMQ that supports service contracts using ServiceProxy. 13 | Copyright 2014 Manuel Felício 14 | zmq zeromq 0mq messaging services request reply proxy async asynchronous 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/Redis/Server/Program.cs: -------------------------------------------------------------------------------- 1 | using ServiceProxy.Redis; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Server 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | var serviceFactory = new ServiceProxy.ServiceFactory(new SimpleDependencyResolver()); 15 | 16 | using (var server = new RedisServer(new RedisConnection("localhost"), "ThisIsTheServiceQueue", serviceFactory)) 17 | { 18 | server.Listen(); 19 | 20 | Console.WriteLine("Press ENTER to close"); 21 | Console.ReadLine(); 22 | } 23 | } 24 | } 25 | 26 | //This should be an adapter for an IoC container 27 | class SimpleDependencyResolver : ServiceProxy.IDependencyResolver 28 | { 29 | public object Resolve(Type type) 30 | { 31 | return new FooService(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/App_Start/ServiceProxyAutofacModule.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using MyApp.Services; 3 | using ServiceProxy; 4 | using ServiceProxy.Zmq; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Web; 9 | 10 | namespace MyApp.WebAPI 11 | { 12 | public class ServiceProxyAutofacModule : Module 13 | { 14 | protected override void Load(Autofac.ContainerBuilder builder) 15 | { 16 | builder.RegisterType().As().SingleInstance(); 17 | 18 | builder.RegisterInstance(new ZmqClient(new ZMQ.Context(), "tcp://localhost:8001", "tcp://localhost:8002")) 19 | .As().SingleInstance(); 20 | 21 | builder.Register(ctx => ctx.Resolve().CreateServiceClient(15000)); 22 | builder.Register(ctx => ctx.Resolve().CreateServiceClient(15000)); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /nuget/ServiceProxy.Redis/ServiceProxy.Redis.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ServiceProxy.Redis 5 | 1.1.0 6 | ServiceProxy.Redis 7 | Manuel Felicio 8 | Manuel Felicio 9 | http://opensource.org/licenses/mit-license.php 10 | http://github.com/mfelicio/ServiceProxy 11 | false 12 | ServiceProxy.Redis is a simple request/reply messaging framework built on Redis queues that support service contracts using ServiceProxy and the StackExchange.Redis library. 13 | Copyright 2014 Manuel Felício 14 | redis messaging services request reply proxy async asynchronous 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/Controllers/CatalogController.cs: -------------------------------------------------------------------------------- 1 | using MyApp.Services; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Threading.Tasks; 8 | using System.Web.Http; 9 | 10 | namespace MyApp.WebAPI.Controllers 11 | { 12 | public class CatalogController : ApiController 13 | { 14 | private readonly ICatalogService catalogService; 15 | 16 | public CatalogController(ICatalogService catalogService) 17 | { 18 | this.catalogService = catalogService; 19 | } 20 | 21 | public IEnumerable GetCatalogNames() 22 | { 23 | return this.catalogService.GetCatalogNames(); 24 | } 25 | 26 | public Catalog GetCatalogs(string name) 27 | { 28 | return this.catalogService.GetCatalog(name); 29 | } 30 | 31 | public ItemDetails GetDetails(string code) 32 | { 33 | return this.catalogService.GetItemDetails(code); 34 | } 35 | 36 | } 37 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Manuel Felicio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/Controllers/AsyncCatalogController.cs: -------------------------------------------------------------------------------- 1 | using MyApp.Services; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Threading.Tasks; 8 | using System.Web.Http; 9 | 10 | namespace MyApp.WebAPI.Controllers 11 | { 12 | public class AsyncCatalogController : ApiController 13 | { 14 | private readonly ICatalogService catalogService; 15 | 16 | public AsyncCatalogController(ICatalogService catalogService) 17 | { 18 | this.catalogService = catalogService; 19 | } 20 | 21 | public async Task> GetCatalogNamesAsync() 22 | { 23 | return await this.catalogService.GetCatalogNamesAsync(); 24 | } 25 | 26 | public async Task GetCatalogAsync(string name) 27 | { 28 | return await this.catalogService.GetCatalogAsync(name); 29 | } 30 | 31 | public async Task GetDetailsAsync(string code) 32 | { 33 | return await this.catalogService.GetItemDetailsAsync(code); 34 | } 35 | 36 | } 37 | } -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/App_Start/AutofacConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Web; 4 | using System.Web.Http; 5 | using System.Web.Http.Description; 6 | using System.Web.Http.Dispatcher; 7 | using System.Web.Routing; 8 | using Swagger.Net; 9 | using Autofac; 10 | using Autofac.Integration.WebApi; 11 | 12 | [assembly: WebActivator.PreApplicationStartMethod(typeof(MyApp.WebAPI.AutofacConfig), "PreStart")] 13 | [assembly: WebActivator.PostApplicationStartMethod(typeof(MyApp.WebAPI.AutofacConfig), "PostStart")] 14 | 15 | namespace MyApp.WebAPI 16 | { 17 | public static class AutofacConfig 18 | { 19 | public static void PreStart() 20 | { 21 | } 22 | 23 | public static void PostStart() 24 | { 25 | var builder = new ContainerBuilder(); 26 | 27 | builder.RegisterApiControllers(typeof(WebApiApplication).Assembly); 28 | 29 | builder.RegisterModule(new ServiceProxyAutofacModule()); 30 | 31 | var container = builder.Build(); 32 | 33 | GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/RedisConnection.cs: -------------------------------------------------------------------------------- 1 | using StackExchange.Redis; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ServiceProxy.Redis 9 | { 10 | public class RedisConnection 11 | { 12 | private readonly ConnectionMultiplexer connectionManager; 13 | 14 | public RedisConnection(string host, int port = 6379, string password = null) 15 | { 16 | var options = new ConfigurationOptions(); 17 | options.Password = password; 18 | options.EndPoints.Add(host, port); 19 | options.AbortOnConnectFail = false; 20 | 21 | this.connectionManager = ConnectionMultiplexer.Connect(options); 22 | } 23 | 24 | public RedisConnection(ConnectionMultiplexer connectionMultiplexer) 25 | { 26 | this.connectionManager = connectionMultiplexer; 27 | } 28 | 29 | public IDatabase GetClient() 30 | { 31 | return this.connectionManager.GetDatabase(); 32 | } 33 | 34 | public ISubscriber GetSubscriber() 35 | { 36 | return this.connectionManager.GetSubscriber(); 37 | } 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Broker/Program.cs: -------------------------------------------------------------------------------- 1 | using ServiceProxy.Zmq; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace MyApp.Broker 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | //Note: 0MQ tcp sockets only accept IPv4 addresses, wild card or interface-name for the Bind operation. 15 | var clientInboundAddr = "tcp://*:8001"; 16 | var clientOutboundAddr = "tcp://*:8002"; 17 | var serverInboundAddr = "tcp://*:8003"; 18 | var serverOutboundAddr = "tcp://*:8004"; 19 | 20 | ZmqBroker broker = null; 21 | 22 | try 23 | { 24 | broker = new ZmqBroker(new ZMQ.Context(), clientInboundAddr, clientOutboundAddr, serverInboundAddr, serverOutboundAddr); 25 | broker.Listen(); 26 | 27 | Console.WriteLine("Press enter to quit"); 28 | Console.ReadLine(); 29 | } 30 | finally 31 | { 32 | if (broker != null) 33 | { 34 | broker.Dispose(); 35 | } 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MyApp.WebAPI")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MyApp.WebAPI")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("83ca4f48-8fe8-450b-b363-78ef4fd8161b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /examples/Redis/Client/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Client")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Client")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("56e8fd63-0803-48c2-972f-cf7094f783c3")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /examples/Redis/Server/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Server")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Server")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("63f9d189-6b84-419b-89b3-5c94e1deb822")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/ServiceProxy/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceProxy")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServiceProxy")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c9b2f8e2-ff3a-4ff7-ae04-9929341271cc")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Broker/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MyApp.Broker")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MyApp.Broker")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("705fc4da-53df-45c5-a6da-c78bb3125e2f")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Worker/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MyApp.Worker")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MyApp.Worker")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("03fedb7f-8264-45e2-abf4-cc1780d7aab4")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Services/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MyApp.Services")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MyApp.Services")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9a43bd0e-9ef4-4d16-b7ce-e7f405338ee0")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceProxy.Zmq")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServiceProxy.Zmq")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("305937fe-d692-4286-b26a-9ab71e832a59")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /examples/Redis/ServiceContracts/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceContracts")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServiceContracts")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("951b290e-613c-4182-a174-1a17a7721eae")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceProxy.Redis")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServiceProxy.Redis")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("0f571330-451b-49ee-a2ca-1c8e98cf6813")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/ServiceProxy.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceProxy.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServiceProxy.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d4a72aa0-89fe-4afd-9efc-71b5decc3470")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceProxy.Zmq")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServiceProxy.Zmq")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a4a134b9-369d-4852-8df3-7d18d58f78a1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceProxy.Zmq.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServiceProxy.Zmq.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("2e5711dc-19ff-4837-b70d-b199f9f4c7a6")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceProxy.Zmq.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServiceProxy.Zmq.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("a1f31be4-f94b-4b2d-8641-76619deaae6e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Web.Http; 5 | 6 | namespace MyApp.WebAPI 7 | { 8 | public static class WebApiConfig 9 | { 10 | public static void Register(HttpConfiguration config) 11 | { 12 | config.Routes.MapHttpRoute( 13 | name: "DefaultApi", 14 | routeTemplate: "api/swagger/{id}", 15 | defaults: new { id = RouteParameter.Optional, controller = "swagger" } 16 | ); 17 | 18 | config.Routes.MapHttpRoute( 19 | name: "Default2Api", 20 | routeTemplate: "api/{controller}/{action}/{id}", 21 | defaults: new { id = RouteParameter.Optional } 22 | ); 23 | 24 | // Uncomment the following line of code to enable query support for actions with an IQueryable or IQueryable return type. 25 | // To avoid processing unexpected or malicious queries, use the validation settings on QueryableAttribute to validate incoming queries. 26 | // For more information, visit http://go.microsoft.com/fwlink/?LinkId=279712. 27 | //config.EnableQuerySupport(); 28 | 29 | // To disable tracing in your application, please comment out or remove the following line of code 30 | // For more information, refer to: http://www.asp.net/web-api 31 | config.EnableSystemDiagnosticsTracing(); 32 | 33 | config.Formatters.Remove(config.Formatters.XmlFormatter); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /source/ServiceProxy.Redis.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("ServiceProxy.Redis.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("ServiceProxy.Redis.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("bf5ebdac-5aa8-4ee1-9871-dd76fc852961")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Services.InMemory/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MyApp.Services.InMemory")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MyApp.Services.InMemory")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("9de742f5-57a0-4d0b-9781-f42da90ce9c4")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/App_Start/SwaggerNet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Web; 4 | using System.Web.Http; 5 | using System.Web.Http.Description; 6 | using System.Web.Http.Dispatcher; 7 | using System.Web.Routing; 8 | using Swagger.Net; 9 | 10 | [assembly: WebActivator.PreApplicationStartMethod(typeof(MyApp.WebAPI.SwaggerNet), "PreStart")] 11 | [assembly: WebActivator.PostApplicationStartMethod(typeof(MyApp.WebAPI.SwaggerNet), "PostStart")] 12 | 13 | namespace MyApp.WebAPI 14 | { 15 | public static class SwaggerNet 16 | { 17 | public static void PreStart() 18 | { 19 | RouteTable.Routes.MapHttpRoute( 20 | name: "SwaggerApi", 21 | routeTemplate: "api/docs/{controller}", 22 | defaults: new { swagger = true } 23 | ); 24 | } 25 | 26 | public static void PostStart() 27 | { 28 | var config = GlobalConfiguration.Configuration; 29 | 30 | config.Filters.Add(new SwaggerActionFilter()); 31 | 32 | try 33 | { 34 | config.Services.Replace(typeof(IDocumentationProvider), 35 | new XmlCommentDocumentationProvider(HttpContext.Current.Server.MapPath("~/bin/MyApp.WebAPI.XML"))); 36 | } 37 | catch (FileNotFoundException) 38 | { 39 | throw new Exception("Please enable \"XML documentation file\" in project properties with default (bin\\MyApp.WebAPI.XML) value or edit value in App_Start\\SwaggerNet.cs"); 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.Serialization.Formatters.Binary; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace ServiceProxy.Zmq 10 | { 11 | static class ArrayExtensions 12 | { 13 | public static T[] Slice(this T[] data, int index, int length) 14 | { 15 | T[] slice = new T[length]; 16 | Array.Copy(data, index, slice, 0, length); 17 | return slice; 18 | } 19 | 20 | public static byte[] ToBinary(T obj) 21 | { 22 | var formatter = new BinaryFormatter(); 23 | 24 | using (var stream = new MemoryStream()) 25 | { 26 | formatter.Serialize(stream, obj); 27 | return stream.GetBuffer(); 28 | } 29 | 30 | } 31 | 32 | public static T ToObject(byte[] objBytes) 33 | { 34 | var formatter = new BinaryFormatter(); 35 | 36 | using (var stream = new MemoryStream(objBytes)) 37 | { 38 | return (T)formatter.Deserialize(stream); 39 | } 40 | } 41 | } 42 | 43 | static class ZmqContextExtensions 44 | { 45 | public static Guid NewIdentity(this ZMQ.Context context) 46 | { 47 | Guid identity; 48 | while (true) 49 | { 50 | identity = Guid.NewGuid(); 51 | if (identity.ToByteArray()[0] != 0) 52 | { 53 | return identity; 54 | } 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.Serialization.Formatters.Binary; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace ServiceProxy.Redis 10 | { 11 | static class ArrayExtensions 12 | { 13 | public static T[] Slice(this T[] data, int index, int length) 14 | { 15 | T[] slice = new T[length]; 16 | Array.Copy(data, index, slice, 0, length); 17 | return slice; 18 | } 19 | 20 | public static byte[] ToBinary(T obj) 21 | { 22 | var formatter = new BinaryFormatter(); 23 | 24 | using (var stream = new MemoryStream()) 25 | { 26 | formatter.Serialize(stream, obj); 27 | return stream.GetBuffer(); 28 | } 29 | 30 | } 31 | 32 | public static T ToObject(byte[] objBytes) 33 | { 34 | var formatter = new BinaryFormatter(); 35 | 36 | using (var stream = new MemoryStream(objBytes)) 37 | { 38 | return (T)formatter.Deserialize(stream); 39 | } 40 | } 41 | } 42 | 43 | static class TaskExtensions 44 | { 45 | public static async Task IgnoreException(this Task task, params Type[] exceptionTypes) 46 | { 47 | try 48 | { 49 | return await task; 50 | } 51 | catch (Exception ex) 52 | { 53 | if (exceptionTypes.Any(type => type.IsAssignableFrom(ex.GetType()))) 54 | { 55 | return default(T); 56 | } 57 | 58 | throw; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Services.InMemory/FooService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace MyApp.Services.InMemory 8 | { 9 | public class FooService : IFooService 10 | { 11 | private readonly ICatalogService catalogService; 12 | 13 | public FooService(ICatalogService catalogService) 14 | { 15 | this.catalogService = catalogService; 16 | } 17 | 18 | public void DoNothing() 19 | { 20 | //like nothing 21 | } 22 | 23 | public async Task AsyncOperationThatTakesTimeAndMayFail(int operationTime, bool fail) 24 | { 25 | await Task.Delay(operationTime); 26 | 27 | if (fail) 28 | { 29 | throw new ApplicationException("You asked for it!"); 30 | } 31 | } 32 | 33 | public IAsyncResult BeginSum(int arg1, int arg2, AsyncCallback asyncCallback, object asyncState) 34 | { 35 | var t = Task.Factory.StartNew((s) => arg1 + arg2, asyncState); 36 | 37 | //introducing some delay on purpose and signaling completion when the sum and the delay are done 38 | Task.Factory.ContinueWhenAll(new Task[] { t, Task.Delay(50)}, ts => asyncCallback(t)); 39 | 40 | return t; 41 | } 42 | 43 | public int EndSum(IAsyncResult asyncResult) 44 | { 45 | var t = asyncResult as Task; 46 | return t.Result; 47 | } 48 | 49 | public Catalog GetRandomCatalog() 50 | { 51 | var random = new Random(); 52 | var names = this.catalogService.GetCatalogNames().ToArray(); 53 | 54 | var catalogName = names[random.Next(names.Length)]; 55 | 56 | return this.catalogService.GetCatalog(catalogName); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq/README.md: -------------------------------------------------------------------------------- 1 | ServiceProxy.Zmq 2 | ============ 3 | 4 | ServiceProxy.Zmq is a scalable request/reply messaging framework built with ZeroMQ that supports service contracts using ServiceProxy. 5 | 6 | ## Getting started 7 | 8 | The quickest way to get started is to use the [Nuget package][serviceproxy.zmq-nuget]. 9 | 10 | ### Example from a unit test in ServiceProxy.Zmq.Tests 11 | 12 | ```c# 13 | public async void TestSendAndReceive() 14 | { 15 | var resolver = new DependencyResolver(); 16 | 17 | using (var broker = new ZmqBroker(this.zmqContext, ClientInboundAddress, ClientOutboundAddress, ServerInboundAddress, ServerOutboundAddress)) 18 | { 19 | broker.Listen(); 20 | 21 | using (var server = new ZmqServer(this.zmqContext, ServerInboundAddress, ServerOutboundAddress, new ServiceFactory(resolver))) 22 | { 23 | server.Listen(); 24 | 25 | using (var client = new ZmqClient(this.zmqContext, ClientInboundAddress, ClientOutboundAddress)) 26 | { 27 | var clientFactory = new ServiceClientFactory(client); 28 | 29 | var serviceClient = clientFactory.CreateServiceClient(); 30 | 31 | Assert.That(serviceClient.GetPerson(1), Is.Not.Null); 32 | 33 | var persons = await serviceClient.ListPersonsAsync(5); 34 | Assert.That(persons, Is.Not.Null); 35 | Assert.AreEqual(5, persons.Count()); 36 | } 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | The ZmqClient, ZmqBroker and ZmqServer instances should be created in different processes/machines. It supports load balancing by having multiple ZmqServer instances connected to the ZmqBroker. 43 | 44 | ## Dependencies 45 | 46 | ServiceProxy.Zmq uses the [clrzmq][clrzmq-github] ZeroMQ binding for .NET. This version uses libzmq 3.2.2-rc2. 47 | 48 | [serviceproxy.zmq-nuget]: http://www.nuget.org/packages/ServiceProxy.Zmq 49 | [clrzmq-github]: https://github.com/zeromq/clrzmq 50 | 51 | -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/README.md: -------------------------------------------------------------------------------- 1 | ServiceProxy.Redis 2 | ============ 3 | 4 | ServiceProxy.Redis is a simple request/reply messaging framework built on Redis queues that supports service contracts using ServiceProxy. 5 | 6 | ## Getting started 7 | 8 | The quickest way to get started is to use the [Nuget package][serviceproxy.redis-nuget]. 9 | 10 | ### Example from a unit test in ServiceProxy.Redis.Tests 11 | 12 | ```c# 13 | public async void TestSendAndReceive() 14 | { 15 | var resolver = new DependencyResolver(); 16 | 17 | using (var server = new RedisServer(new RedisConnection(RedisHost, RedisPort, RedisPassword), ServerQueue, new ServiceFactory(resolver))) 18 | { 19 | server.Listen(); 20 | 21 | using (var client = new RedisClient(new RedisConnection(RedisHost, RedisPort, RedisPassword), ClientQueue, ServerQueue)) 22 | { 23 | var clientFactory = new ServiceProxy.ServiceClientFactory(client); 24 | 25 | var serviceClient = clientFactory.CreateServiceClient(); 26 | 27 | Assert.That(serviceClient.GetPerson(1), Is.Not.Null); 28 | 29 | var persons = await serviceClient.ListPersonsAsync(5); 30 | Assert.That(persons, Is.Not.Null); 31 | Assert.AreEqual(5, persons.Count()); 32 | } 33 | } 34 | } 35 | ``` 36 | 37 | The client and server should be created in different processes/machines, using Redis as a middleware and ServiceProxy to support service contracts. 38 | 39 | It supports load balancing by having multiple servers listening on the same Redis queue. 40 | 41 | ## Dependencies 42 | 43 | ServiceProxy.Redis now uses the [StackExchange.Redis][stackexchange.redis-github] client library, the successor of the [Booksleeve][booksleeve-home] Redis client library. 44 | 45 | [serviceproxy.redis-nuget]: http://www.nuget.org/packages/ServiceProxy.Redis 46 | [booksleeve-home]: https://code.google.com/p/booksleeve/ 47 | [stackexchange.redis-github]: https://github.com/StackExchange/StackExchange.Redis 48 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /source/ServiceProxy/ServiceFactory.cs: -------------------------------------------------------------------------------- 1 | using ServiceProxy.Internal; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace ServiceProxy 11 | { 12 | public class ServiceFactory : IServiceFactory 13 | { 14 | private readonly IDependencyResolver resolver; 15 | //using Lazy with ConcurrentDictionary ensures that the CreateNewService method will only be invoked once per serviceType 16 | private readonly ConcurrentDictionary> services; 17 | 18 | private readonly ConcurrentDictionary serviceNamesMap; 19 | 20 | public ServiceFactory(IDependencyResolver resolver) 21 | { 22 | this.resolver = resolver; 23 | this.services = new ConcurrentDictionary>(); 24 | this.serviceNamesMap = new ConcurrentDictionary(); 25 | } 26 | 27 | public IService CreateService() 28 | where TService : class 29 | { 30 | return this.CreateService(typeof(TService)); 31 | } 32 | 33 | public IService CreateService(string serviceName) 34 | { 35 | var serviceType = this.serviceNamesMap.GetOrAdd(serviceName, name => Type.GetType(name)); 36 | 37 | return this.CreateService(serviceType); 38 | } 39 | 40 | public IService CreateService(Type serviceType) 41 | { 42 | var service = this.services.GetOrAdd(serviceType, 43 | type => new Lazy(() => this.CreateNewService(type), LazyThreadSafetyMode.ExecutionAndPublication)); 44 | return service.Value; 45 | } 46 | 47 | private IService CreateNewService(Type serviceType) 48 | { 49 | return new Service(serviceType, this.resolver.Resolve(serviceType)); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/Redis/Server/FooService.cs: -------------------------------------------------------------------------------- 1 | using ServiceContracts; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Server 10 | { 11 | public class FooService : IFooService 12 | { 13 | public Foo GetFoo(int id) 14 | { 15 | return FooDb.Get(id); 16 | } 17 | 18 | public IEnumerable ListFoos() 19 | { 20 | return FooDb.All(); 21 | } 22 | 23 | public void UpdateFoo(Foo foo) 24 | { 25 | FooDb.Update(foo); 26 | } 27 | 28 | public Task GetFooAsync(int id) 29 | { 30 | return Task.FromResult(this.GetFoo(id)); 31 | } 32 | 33 | public Task> ListFoosAsync() 34 | { 35 | return Task.FromResult(this.ListFoos()); 36 | } 37 | 38 | public async Task UpdateFooAsync(Foo foo) 39 | { 40 | await Task.Delay(100); //lets introduce some latency 41 | 42 | this.UpdateFoo(foo); 43 | } 44 | } 45 | 46 | static class FooDb 47 | { 48 | static readonly ConcurrentDictionary foos; 49 | 50 | static FooDb() 51 | { 52 | var data = Enumerable.Range(1, 10) 53 | .Select(i => new Foo { Id = i, Name = string.Format("Foo {0}", i) }); 54 | 55 | foos = new ConcurrentDictionary(data.ToDictionary(f => f.Id, f => f)); 56 | } 57 | 58 | public static Foo Get(int id) 59 | { 60 | Foo foo; 61 | foos.TryGetValue(id, out foo); 62 | return foo; 63 | } 64 | 65 | public static void Update(Foo foo) 66 | { 67 | foos.AddOrUpdate(foo.Id, foo, (id, old) => foo); 68 | } 69 | 70 | public static IEnumerable All() 71 | { 72 | return foos.Values.ToArray(); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Services/Model.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Runtime.Serialization; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace MyApp.Services 9 | { 10 | //The Serializable attributes are only necessary because the serializer being used by ServiceProxy.Zmq is the BinaryFormatter 11 | //This will be removed when/if support is added for different serializers 12 | //Note: ServiceProxy itself has no dependencies or notions of serialization 13 | 14 | [Serializable] 15 | [DataContract] 16 | public class Catalog 17 | { 18 | [DataMember] 19 | public string Name { get; set; } 20 | 21 | [DataMember] 22 | public IEnumerable Items { get; set; } 23 | } 24 | 25 | [Serializable] 26 | [DataContract] 27 | public class Item 28 | { 29 | [DataMember] 30 | public string Code { get; set; } 31 | 32 | [DataMember] 33 | public string Description { get; set; } 34 | 35 | [DataMember] 36 | public decimal Price { get; set; } 37 | } 38 | 39 | [Serializable] 40 | [DataContract] 41 | public class ItemDetails 42 | { 43 | [DataMember] 44 | public Item Item { get; set; } 45 | 46 | [DataMember] 47 | public DateTime DateTimeField { get; set; } 48 | [DataMember] 49 | public int IntField { get; set; } 50 | [DataMember] 51 | public long LongField { get; set; } 52 | [DataMember] 53 | public double? NullableDoubleField { get; set; } 54 | [DataMember] 55 | public Guid GuidField { get; set; } 56 | [DataMember] 57 | public IEnumerable RandomTypeField { get; set; } 58 | } 59 | 60 | [Serializable] 61 | [DataContract] 62 | public class RandomType 63 | { 64 | [DataMember] 65 | public int[] IntArrayField { get; set; } 66 | [DataMember] 67 | public char CharField { get; set; } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /source/ServiceProxy/Internal/TimeoutClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace ServiceProxy.Internal 9 | { 10 | public class TimeoutClient : IClient 11 | { 12 | private readonly IClient client; 13 | private readonly TimeSpan timeout; 14 | 15 | private readonly ResponseData timeoutResponse; 16 | 17 | public TimeoutClient(IClient client, TimeSpan timeout) 18 | { 19 | this.client = client; 20 | this.timeout = timeout; 21 | this.timeoutResponse = new ResponseData(new TimeoutException()); 22 | } 23 | 24 | public Task Request(RequestData request, CancellationToken _) 25 | { 26 | var cancellation = new CancellationTokenSource(this.timeout); 27 | 28 | var responseTask = this.client.Request(request, cancellation.Token); 29 | 30 | var completion = new TaskCompletionSource(); 31 | 32 | //when the token reaches timeout, tries to set the timeoutResponse as the result 33 | //if the responseTask already completed, this is ignored 34 | cancellation.Token.Register(() => completion.TrySetResult(this.timeoutResponse)); 35 | 36 | //when the responseTask completes, tries to apply its exception/result properties as long as the timeout isn't reached 37 | responseTask.ContinueWith(t => 38 | { 39 | if (!cancellation.IsCancellationRequested) 40 | { 41 | if (responseTask.Exception != null) 42 | { 43 | completion.TrySetException(responseTask.Exception.InnerException); 44 | } 45 | else 46 | { 47 | completion.TrySetResult(responseTask.Result); 48 | } 49 | } 50 | }); 51 | 52 | return completion.Task; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.meta 24 | *.obj 25 | *.dll 26 | *.dll.config 27 | *.pch 28 | *.pdb 29 | *.pgc 30 | *.pgd 31 | *.rsp 32 | *.sbr 33 | *.tlb 34 | *.tli 35 | *.tlh 36 | *.tmp 37 | *.log 38 | *.vspscc 39 | *.vssscc 40 | .builds 41 | 42 | # Visual C++ cache files 43 | ipch/ 44 | *.aps 45 | *.ncb 46 | *.opensdf 47 | *.sdf 48 | 49 | # Visual Studio profiler 50 | *.psess 51 | *.vsp 52 | *.vspx 53 | 54 | # Guidance Automation Toolkit 55 | *.gpState 56 | 57 | # ReSharper is a .NET coding add-in 58 | _ReSharper* 59 | 60 | # NCrunch 61 | *.ncrunch* 62 | .*crunch*.local.xml 63 | 64 | # Installshield output folder 65 | [Ee]xpress 66 | 67 | # DocProject is a documentation generator add-in 68 | DocProject/buildhelp/ 69 | DocProject/Help/*.HxT 70 | DocProject/Help/*.HxC 71 | DocProject/Help/*.hhc 72 | DocProject/Help/*.hhk 73 | DocProject/Help/*.hhp 74 | DocProject/Help/Html2 75 | DocProject/Help/html 76 | 77 | # Click-Once directory 78 | publish 79 | 80 | # Publish Web Output 81 | *.Publish.xml 82 | 83 | # NuGet Packages Directory 84 | packages 85 | *.nupkg 86 | 87 | # Windows Azure Build Output 88 | csx 89 | *.build.csdef 90 | 91 | # Windows Store app package directory 92 | AppPackages/ 93 | 94 | # Others 95 | [Bb]in 96 | [Oo]bj 97 | sql 98 | TestResults 99 | [Tt]est[Rr]esult* 100 | *.Cache 101 | ClientBin 102 | [Ss]tyle[Cc]op.* 103 | ~$* 104 | *.dbmdl 105 | Generated_Code #added for RIA/Silverlight projects 106 | 107 | # Backup & report files from converting an old project file to a newer 108 | # Visual Studio version. Backup files are not needed, because we have git ;-) 109 | _UpgradeReport_Files/ 110 | Backup*/ 111 | UpgradeLog*.XML 112 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/Controllers/FooController.cs: -------------------------------------------------------------------------------- 1 | using MyApp.Services; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using System.Web; 7 | using System.Web.Http; 8 | 9 | namespace MyApp.WebAPI.Controllers 10 | { 11 | public class FooController : ApiController 12 | { 13 | private readonly IFooService fooService; 14 | 15 | public FooController(IFooService fooService) 16 | { 17 | this.fooService = fooService; 18 | } 19 | 20 | /// 21 | /// Invokes fooService.DoNothing 22 | /// 23 | public void DoNothing() 24 | { 25 | this.fooService.DoNothing(); 26 | } 27 | 28 | /// 29 | /// Invokes fooService.AsyncOperationThatTakesTimeAndMayFail 30 | /// 31 | /// The time the operation will take to complete 32 | /// If true, the operation will complete with an exception 33 | /// 34 | public async Task AsyncOperationThatTakesTimeAndMayFail(int operationTime, bool fail) 35 | { 36 | await this.fooService.AsyncOperationThatTakesTimeAndMayFail(operationTime, fail); 37 | } 38 | 39 | /// 40 | /// Invokes fooService.BeginSum/EndSum to get the sum of two arguments 41 | /// 42 | /// 43 | /// 44 | /// 45 | public async Task Sum(int arg1, int arg2) 46 | { 47 | var sumResult = await Task.Factory.FromAsync(this.fooService.BeginSum, this.fooService.EndSum, arg1, arg2, null); 48 | return sumResult; 49 | } 50 | 51 | /// 52 | /// Invokes fooService.GetRandomCatalog to get a random catalog 53 | /// 54 | /// 55 | public Catalog GetRandomCatalog() 56 | { 57 | return this.fooService.GetRandomCatalog(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq/ZmqResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy.Zmq 8 | { 9 | /// 10 | /// Raw format: HeaderSize + Header + Data 11 | /// Header format: RequestId 12 | /// Data: Result 13 | /// 14 | class ZmqResponse 15 | { 16 | public ZmqResponse(string requestId, ResponseData response) 17 | { 18 | this.RequestId = requestId; 19 | this.Response = response; 20 | } 21 | 22 | public string RequestId { get; private set; } 23 | public ResponseData Response { get; private set; } 24 | 25 | public byte[] ToBinary() 26 | { 27 | var requestIdBytes = Encoding.UTF8.GetBytes(this.RequestId); 28 | var requestIdSizeBytes = BitConverter.GetBytes(requestIdBytes.Length); 29 | 30 | var responseBytes = ArrayExtensions.ToBinary(this.Response); 31 | 32 | var zmqResponseBytes = new byte[requestIdSizeBytes.Length + requestIdBytes.Length + responseBytes.Length]; 33 | 34 | //Copy header size 35 | Array.Copy(requestIdSizeBytes, 0, zmqResponseBytes, 0, requestIdSizeBytes.Length); 36 | 37 | //Copy header 38 | Array.Copy(requestIdBytes, 0, zmqResponseBytes, requestIdSizeBytes.Length, requestIdBytes.Length); 39 | 40 | //Copy result 41 | Array.Copy(responseBytes, 0, zmqResponseBytes, requestIdSizeBytes.Length + requestIdBytes.Length, responseBytes.Length); 42 | 43 | return zmqResponseBytes; 44 | 45 | } 46 | 47 | public static ZmqResponse FromBinary(byte[] zmqResponseBytes) 48 | { 49 | var requestIdSize = BitConverter.ToInt32(zmqResponseBytes.Slice(0, 4), 0); 50 | var requestId = Encoding.UTF8.GetString(zmqResponseBytes.Slice(4, requestIdSize)); 51 | 52 | var responseBytes = zmqResponseBytes.Slice(4 + requestIdSize, zmqResponseBytes.Length - (4 + requestIdSize)); 53 | var response = ArrayExtensions.ToObject(responseBytes); 54 | 55 | return new ZmqResponse(requestId, response); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old/ZmqResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy.Zmq 8 | { 9 | /// 10 | /// Raw format: HeaderSize + Header + Data 11 | /// Header format: RequestId 12 | /// Data: Result 13 | /// 14 | class ZmqResponse 15 | { 16 | public ZmqResponse(string requestId, ResponseData response) 17 | { 18 | this.RequestId = requestId; 19 | this.Response = response; 20 | } 21 | 22 | public string RequestId { get; private set; } 23 | public ResponseData Response { get; private set; } 24 | 25 | public byte[] ToBinary() 26 | { 27 | var requestIdBytes = Encoding.UTF8.GetBytes(this.RequestId); 28 | var requestIdSizeBytes = BitConverter.GetBytes(requestIdBytes.Length); 29 | 30 | var responseBytes = ArrayExtensions.ToBinary(this.Response); 31 | 32 | var zmqResponseBytes = new byte[requestIdSizeBytes.Length + requestIdBytes.Length + responseBytes.Length]; 33 | 34 | //Copy header size 35 | Array.Copy(requestIdSizeBytes, 0, zmqResponseBytes, 0, requestIdSizeBytes.Length); 36 | 37 | //Copy header 38 | Array.Copy(requestIdBytes, 0, zmqResponseBytes, requestIdSizeBytes.Length, requestIdBytes.Length); 39 | 40 | //Copy result 41 | Array.Copy(responseBytes, 0, zmqResponseBytes, requestIdSizeBytes.Length + requestIdBytes.Length, responseBytes.Length); 42 | 43 | return zmqResponseBytes; 44 | 45 | } 46 | 47 | public static ZmqResponse FromBinary(byte[] zmqResponseBytes) 48 | { 49 | var requestIdSize = BitConverter.ToInt32(zmqResponseBytes.Slice(0, 4), 0); 50 | var requestId = Encoding.UTF8.GetString(zmqResponseBytes.Slice(4, requestIdSize)); 51 | 52 | var responseBytes = zmqResponseBytes.Slice(4 + requestIdSize, zmqResponseBytes.Length - (4 + requestIdSize)); 53 | var response = ArrayExtensions.ToObject(responseBytes); 54 | 55 | return new ZmqResponse(requestId, response); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /source/ServiceProxy/ServiceClientFactory.cs: -------------------------------------------------------------------------------- 1 | using Castle.DynamicProxy; 2 | using ServiceProxy.Internal; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Reflection; 8 | using System.Text; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace ServiceProxy 13 | { 14 | public class ServiceClientFactory : IServiceClientFactory 15 | { 16 | private readonly ProxyGenerator proxyGenerator; 17 | //using Lazy with ConcurrentDictionary ensures that the GenerateClientProxy method will only be invoked once per serviceType 18 | private readonly ConcurrentDictionary> clients; 19 | 20 | private readonly IClient client; 21 | 22 | public ServiceClientFactory(IClient client) 23 | { 24 | this.proxyGenerator = new ProxyGenerator(); 25 | this.clients = new ConcurrentDictionary>(); 26 | 27 | this.client = client; 28 | } 29 | 30 | public TService CreateServiceClient(int? timeout = null) 31 | where TService : class 32 | { 33 | var serviceClient = (TService)this.CreateServiceClient(typeof(TService), timeout); 34 | return serviceClient; 35 | } 36 | 37 | public object CreateServiceClient(Type serviceType, int? timeout = null) 38 | { 39 | var client = this.clients.GetOrAdd(serviceType, 40 | type => new Lazy(() => this.GenerateClientProxy(type, timeout), LazyThreadSafetyMode.ExecutionAndPublication)); 41 | return client.Value; 42 | } 43 | 44 | private object GenerateClientProxy(Type serviceType, int? timeout) 45 | { 46 | IClient clientInstance = timeout == null ? this.client : new TimeoutClient(this.client, TimeSpan.FromMilliseconds(timeout.Value)); 47 | 48 | var interceptor = new ServiceClientInterceptor(serviceType, clientInstance); 49 | var proxy = this.proxyGenerator.CreateInterfaceProxyWithoutTarget(serviceType, interceptor); 50 | return proxy; 51 | } 52 | } 53 | 54 | 55 | 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/RedisResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy.Redis 8 | { 9 | /// 10 | /// Raw format: HeaderSize + Header + Data 11 | /// Header format: RequestId 12 | /// Data: Result 13 | /// 14 | class RedisResponse 15 | { 16 | public RedisResponse(string requestId, ResponseData response) 17 | { 18 | this.RequestId = requestId; 19 | this.Response = response; 20 | } 21 | 22 | public string RequestId { get; private set; } 23 | public ResponseData Response { get; private set; } 24 | 25 | public byte[] ToBinary() 26 | { 27 | var requestIdBytes = Encoding.UTF8.GetBytes(this.RequestId); 28 | var requestIdSizeBytes = BitConverter.GetBytes(requestIdBytes.Length); 29 | 30 | var resultBytes = ArrayExtensions.ToBinary(this.Response); 31 | 32 | var redisResponseBytes = new byte[requestIdSizeBytes.Length + requestIdBytes.Length + resultBytes.Length]; 33 | 34 | //Copy header size 35 | Array.Copy(requestIdSizeBytes, 0, redisResponseBytes, 0, requestIdSizeBytes.Length); 36 | 37 | //Copy header 38 | Array.Copy(requestIdBytes, 0, redisResponseBytes, requestIdSizeBytes.Length, requestIdBytes.Length); 39 | 40 | //Copy result 41 | Array.Copy(resultBytes, 0, redisResponseBytes, requestIdSizeBytes.Length + requestIdBytes.Length, resultBytes.Length); 42 | 43 | return redisResponseBytes; 44 | 45 | } 46 | 47 | public static RedisResponse FromBinary(byte[] redisResponseBytes) 48 | { 49 | var requestIdSize = BitConverter.ToInt32(redisResponseBytes.Slice(0, 4), 0); 50 | var requestId = Encoding.UTF8.GetString(redisResponseBytes.Slice(4, requestIdSize)); 51 | 52 | var responseBytes = redisResponseBytes.Slice(4 + requestIdSize, redisResponseBytes.Length - (4 + requestIdSize)); 53 | var response = ArrayExtensions.ToObject(responseBytes); 54 | 55 | return new RedisResponse(requestId, response); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/Redis/RedisSamples.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{B6B77D09-AB39-472B-A0B2-12B153391057}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{6EFA3BF8-D1B0-407B-A3E9-6A35D7AC884B}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceContracts", "ServiceContracts\ServiceContracts.csproj", "{E516D255-31F9-4EBE-A60C-DE755B935ACD}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{04F26D69-AC65-43E4-875A-FF8B99AFF24D}" 11 | ProjectSection(SolutionItems) = preProject 12 | .nuget\NuGet.Config = .nuget\NuGet.Config 13 | .nuget\NuGet.exe = .nuget\NuGet.exe 14 | .nuget\NuGet.targets = .nuget\NuGet.targets 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {B6B77D09-AB39-472B-A0B2-12B153391057}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {B6B77D09-AB39-472B-A0B2-12B153391057}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {B6B77D09-AB39-472B-A0B2-12B153391057}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {B6B77D09-AB39-472B-A0B2-12B153391057}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {6EFA3BF8-D1B0-407B-A3E9-6A35D7AC884B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {6EFA3BF8-D1B0-407B-A3E9-6A35D7AC884B}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {6EFA3BF8-D1B0-407B-A3E9-6A35D7AC884B}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {6EFA3BF8-D1B0-407B-A3E9-6A35D7AC884B}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {E516D255-31F9-4EBE-A60C-DE755B935ACD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {E516D255-31F9-4EBE-A60C-DE755B935ACD}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {E516D255-31F9-4EBE-A60C-DE755B935ACD}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {E516D255-31F9-4EBE-A60C-DE755B935ACD}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Worker/Program.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Extras.DynamicProxy2; 3 | using Castle.DynamicProxy; 4 | using MyApp.Services; 5 | using MyApp.Services.InMemory; 6 | using ServiceProxy; 7 | using ServiceProxy.Zmq; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | 14 | namespace MyApp.Worker 15 | { 16 | class Program 17 | { 18 | static void Main(string[] args) 19 | { 20 | var serverInboundAddr = "tcp://localhost:8003"; 21 | var serverOutboundAddr = "tcp://localhost:8004"; 22 | 23 | var builder = new ContainerBuilder(); 24 | 25 | builder.RegisterType().AsSelf().As(); 26 | 27 | builder.RegisterType().As() 28 | .EnableInterfaceInterceptors() 29 | .InterceptedBy(typeof(LogInterceptor)); ; 30 | builder.RegisterType().As() 31 | .EnableInterfaceInterceptors() 32 | .InterceptedBy(typeof(LogInterceptor)); 33 | 34 | builder.RegisterType().As(); 35 | builder.RegisterType().As(); 36 | 37 | var container = builder.Build(); 38 | 39 | ZmqServer server = null; 40 | try 41 | { 42 | server = new ZmqServer(new ZMQ.Context(), serverInboundAddr, serverOutboundAddr, container.Resolve()); 43 | server.Listen(); 44 | 45 | Console.WriteLine("Press enter to quit"); 46 | Console.ReadLine(); 47 | } 48 | finally 49 | { 50 | if (server != null) 51 | { 52 | server.Dispose(); 53 | } 54 | } 55 | } 56 | } 57 | 58 | public class AutofacDependencyResolver : IDependencyResolver 59 | { 60 | private readonly ILifetimeScope container; 61 | 62 | public AutofacDependencyResolver(ILifetimeScope container) 63 | { 64 | this.container = container; 65 | } 66 | 67 | public object Resolve(Type type) 68 | { 69 | return this.container.Resolve(type); 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /source/ServiceProxy/Internal/Service.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy.Internal 8 | { 9 | internal class Service : IService 10 | { 11 | private readonly object serviceInstance; 12 | 13 | private readonly Dictionary operationInvokers; 14 | 15 | public Service(Type serviceType, object serviceInstance) 16 | { 17 | this.serviceInstance = serviceInstance; 18 | 19 | var serviceMethods = ReflectionUtils.GetServiceOperations(serviceType); 20 | 21 | this.operationInvokers = serviceMethods.Where(m => m.IsSyncOperation()) 22 | .Select(m => new SynchronousOperationInvoker(m) as OperationInvoker) 23 | .Union( 24 | serviceMethods.Where(m => m.IsTaskBasedAsyncOperation()) 25 | .Select(m => new TaskBasedOperationInvoker(m) as OperationInvoker) 26 | ) 27 | .Union( 28 | serviceMethods.Where(m => m.IsAsyncResultBasedOperation()) 29 | .Select(m => new AsyncResultBasedOperation(m) as OperationInvoker) 30 | ) 31 | .ToDictionary(op => op.Name, op => op); 32 | } 33 | 34 | public Task Process(RequestData requestData) 35 | { 36 | var op = this.operationInvokers[requestData.Operation]; 37 | 38 | return op.InvokeAsync(this.serviceInstance, requestData.Arguments) 39 | .ContinueWith(t => 40 | { 41 | if (t.Exception == null) 42 | { 43 | return new ResponseData(t.Result); 44 | } 45 | else 46 | { 47 | return new ResponseData(t.Exception.InnerException); 48 | } 49 | }); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq/ZmqRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy.Zmq 8 | { 9 | /// 10 | /// Raw format: HeaderSize+Header+Data 11 | /// Header format: Id:Service:Operation 12 | /// Data format: byte[](Arguments) 13 | /// 14 | class ZmqRequest 15 | { 16 | public ZmqRequest(string id, RequestData request) 17 | { 18 | this.Id = id; 19 | this.Request = request; 20 | } 21 | 22 | public string Id { get; private set; } 23 | 24 | public RequestData Request { get; private set; } 25 | 26 | public byte[] ToBinary() 27 | { 28 | var header = string.Format("{0}:{1}:{2}", this.Id, this.Request.Service, this.Request.Operation); 29 | 30 | var headerBytes = Encoding.UTF8.GetBytes(header); 31 | var headerSizeBytes = BitConverter.GetBytes(headerBytes.Length); 32 | 33 | var argumentsBytes = ArrayExtensions.ToBinary(this.Request.Arguments); 34 | 35 | var zmqRequestBytes = new byte[4 + headerBytes.Length + argumentsBytes.Length]; 36 | 37 | //copy header size 38 | Array.Copy(headerSizeBytes, 0, zmqRequestBytes, 0, headerSizeBytes.Length); 39 | 40 | //copy header 41 | Array.Copy(headerBytes, 0, zmqRequestBytes, headerSizeBytes.Length, headerBytes.Length); 42 | 43 | //copy arguments 44 | Array.Copy(argumentsBytes, 0, zmqRequestBytes, headerSizeBytes.Length + headerBytes.Length, argumentsBytes.Length); 45 | 46 | return zmqRequestBytes; 47 | } 48 | 49 | public static ZmqRequest FromBinary(byte[] zmqRequestBytes) 50 | { 51 | var headerSize = BitConverter.ToInt32(zmqRequestBytes.Slice(0, 4), 0); 52 | var headerBytes = zmqRequestBytes.Slice(4, headerSize); 53 | var argumentsBytes = zmqRequestBytes.Slice(4 + headerSize, zmqRequestBytes.Length - (4 + headerSize)); 54 | 55 | var header = Encoding.UTF8.GetString(headerBytes); 56 | var headerValues = header.Split(':'); 57 | 58 | var arguments = ArrayExtensions.ToObject(argumentsBytes); 59 | 60 | var request = new RequestData(headerValues[1], headerValues[2], arguments); 61 | 62 | return new ZmqRequest(headerValues[0], request); 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq_old/ZmqRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy.Zmq 8 | { 9 | /// 10 | /// Raw format: HeaderSize+Header+Data 11 | /// Header format: Id:Service:Operation 12 | /// Data format: byte[](Arguments) 13 | /// 14 | class ZmqRequest 15 | { 16 | public ZmqRequest(string id, RequestData request) 17 | { 18 | this.Id = id; 19 | this.Request = request; 20 | } 21 | 22 | public string Id { get; private set; } 23 | 24 | public RequestData Request { get; private set; } 25 | 26 | public byte[] ToBinary() 27 | { 28 | var header = string.Format("{0}:{1}:{2}", this.Id, this.Request.Service, this.Request.Operation); 29 | 30 | var headerBytes = Encoding.UTF8.GetBytes(header); 31 | var headerSizeBytes = BitConverter.GetBytes(headerBytes.Length); 32 | 33 | var argumentsBytes = ArrayExtensions.ToBinary(this.Request.Arguments); 34 | 35 | var zmqRequestBytes = new byte[4 + headerBytes.Length + argumentsBytes.Length]; 36 | 37 | //copy header size 38 | Array.Copy(headerSizeBytes, 0, zmqRequestBytes, 0, headerSizeBytes.Length); 39 | 40 | //copy header 41 | Array.Copy(headerBytes, 0, zmqRequestBytes, headerSizeBytes.Length, headerBytes.Length); 42 | 43 | //copy arguments 44 | Array.Copy(argumentsBytes, 0, zmqRequestBytes, headerSizeBytes.Length + headerBytes.Length, argumentsBytes.Length); 45 | 46 | return zmqRequestBytes; 47 | } 48 | 49 | public static ZmqRequest FromBinary(byte[] zmqRequestBytes) 50 | { 51 | var headerSize = BitConverter.ToInt32(zmqRequestBytes.Slice(0, 4), 0); 52 | var headerBytes = zmqRequestBytes.Slice(4, headerSize); 53 | var argumentsBytes = zmqRequestBytes.Slice(4 + headerSize, zmqRequestBytes.Length - (4 + headerSize)); 54 | 55 | var header = Encoding.UTF8.GetString(headerBytes); 56 | var headerValues = header.Split(':'); 57 | 58 | var arguments = ArrayExtensions.ToObject(argumentsBytes); 59 | 60 | var request = new RequestData(headerValues[1], headerValues[2], arguments); 61 | 62 | return new ZmqRequest(headerValues[0], request); 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /examples/Redis/ServiceContracts/ServiceContracts.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E516D255-31F9-4EBE-A60C-DE755B935ACD} 8 | Library 9 | Properties 10 | ServiceContracts 11 | ServiceContracts 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 54 | -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/RedisRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ServiceProxy.Redis 8 | { 9 | /// 10 | /// Raw format: HeaderSize+Header+Data 11 | /// Header format: ReceiveQueue:Id:Service:Operation 12 | /// Data format: byte[](Arguments) 13 | /// 14 | class RedisRequest 15 | { 16 | public RedisRequest(string receiveQueue, string id, RequestData request) 17 | { 18 | this.ReceiveQueue = receiveQueue; 19 | this.Id = id; 20 | this.Request = request; 21 | } 22 | 23 | public string ReceiveQueue { get; private set; } 24 | public string Id { get; private set; } 25 | 26 | public RequestData Request { get; private set; } 27 | 28 | public byte[] ToBinary() 29 | { 30 | var header = string.Format("{0}:{1}:{2}:{3}", this.ReceiveQueue, this.Id, this.Request.Service, this.Request.Operation); 31 | 32 | var headerBytes = Encoding.UTF8.GetBytes(header); 33 | var headerSizeBytes = BitConverter.GetBytes(headerBytes.Length); 34 | 35 | var argumentsBytes = ArrayExtensions.ToBinary(this.Request.Arguments); 36 | 37 | var redisRequestBytes = new byte[4 + headerBytes.Length + argumentsBytes.Length]; 38 | 39 | //copy header size 40 | Array.Copy(headerSizeBytes, 0, redisRequestBytes, 0, headerSizeBytes.Length); 41 | 42 | //copy header 43 | Array.Copy(headerBytes, 0, redisRequestBytes, headerSizeBytes.Length, headerBytes.Length); 44 | 45 | //copy arguments 46 | Array.Copy(argumentsBytes, 0, redisRequestBytes, headerSizeBytes.Length + headerBytes.Length, argumentsBytes.Length); 47 | 48 | return redisRequestBytes; 49 | } 50 | 51 | public static RedisRequest FromBinary(byte[] redisRequestBytes) 52 | { 53 | var headerSize = BitConverter.ToInt32(redisRequestBytes.Slice(0, 4), 0); 54 | var headerBytes = redisRequestBytes.Slice(4, headerSize); 55 | var argumentsBytes = redisRequestBytes.Slice(4 + headerSize, redisRequestBytes.Length - (4 + headerSize)); 56 | 57 | var header = Encoding.UTF8.GetString(headerBytes); 58 | var headerValues = header.Split(':'); 59 | 60 | var arguments = ArrayExtensions.ToObject(argumentsBytes); 61 | 62 | var request = new RequestData(headerValues[2], headerValues[3], arguments); 63 | 64 | return new RedisRequest(headerValues[0], headerValues[1], request); 65 | } 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Services/MyApp.Services.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CB34E9EF-7223-44A7-AFB1-C0B89DE4B26A} 8 | Library 9 | Properties 10 | MyApp.Services 11 | MyApp.Services 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 56 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain -------------------------------------------------------------------------------- /examples/Redis/Client/Program.cs: -------------------------------------------------------------------------------- 1 | using ServiceContracts; 2 | using ServiceProxy.Redis; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Client 12 | { 13 | class Program 14 | { 15 | static void Main(string[] args) 16 | { 17 | using (var client = new RedisClient(new RedisConnection("localhost"), "ThisIsTheClientQueue", "ThisIsTheServiceQueue")) 18 | { 19 | var clientFactory = new ServiceProxy.ServiceClientFactory(client); 20 | 21 | var fooService = clientFactory.CreateServiceClient(); 22 | 23 | Console.WriteLine("Press ENTER for GetFooAndUpdate test"); 24 | Console.ReadLine(); 25 | 26 | GetFooAndUpdate(fooService); 27 | 28 | Console.WriteLine("Press ENTER for SimpleBenchmark test"); 29 | Console.ReadLine(); 30 | 31 | SimpleBenchmark(fooService).Wait(); 32 | 33 | Console.WriteLine("Press ENTER to exit"); 34 | Console.ReadLine(); 35 | } 36 | } 37 | 38 | static void GetFooAndUpdate(IFooService fooService) 39 | { 40 | var foo = fooService.GetFoo(5); 41 | 42 | if (foo.Name == "Foo 5") 43 | { 44 | foo.Name = "Foo 1337"; 45 | fooService.UpdateFoo(foo); 46 | 47 | var l33t = fooService.GetFoo(5); 48 | if (l33t.Name == "Foo 1337") 49 | { 50 | Console.WriteLine("Successfully updated Foo 5 name to Foo 1337"); 51 | } 52 | } 53 | } 54 | 55 | static async Task SimpleBenchmark(IFooService fooService) 56 | { 57 | var nCalls = 100 * 1000; 58 | 59 | var random = new Random(); 60 | 61 | var tasksToWait = new ConcurrentBag(); 62 | 63 | var sw = Stopwatch.StartNew(); 64 | 65 | Parallel.For(0, nCalls, i => 66 | { 67 | //gets a foo with id between 1 and 10, asynchronously 68 | tasksToWait.Add( 69 | fooService.GetFooAsync(random.Next(1, 11))); 70 | }); 71 | 72 | await Task.WhenAll(tasksToWait.ToArray()); 73 | 74 | sw.Stop(); 75 | 76 | Console.WriteLine("{0} calls completed in {1}", nCalls, sw.Elapsed); 77 | Console.WriteLine("Avg time per call: {0} ms", (double)sw.ElapsedMilliseconds / nCalls); 78 | Console.WriteLine("Requests per second: {0}", (double)nCalls / sw.Elapsed.TotalSeconds); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /source/ServiceProxy.Tests/ClientAndServerTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using ServiceProxy.Tests.Stubs; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace ServiceProxy.Tests 12 | { 13 | public class ClientAndServerTests 14 | { 15 | private readonly IDependencyResolver resolver = new DependencyResolver(); 16 | 17 | [SetUp] 18 | public void Setup() 19 | { 20 | 21 | } 22 | 23 | [TearDown] 24 | public void TearDown() 25 | { 26 | 27 | } 28 | 29 | [Test] 30 | public async void RequestGetsResponseFromServer() 31 | { 32 | var clientFactory = new ServiceClientFactory(new SimpleClient(new ServiceFactory(this.resolver))); 33 | 34 | var serviceClient = clientFactory.CreateServiceClient(); 35 | 36 | //Synchronous 37 | Assert.That(serviceClient.GetPerson(1), Is.Not.Null); 38 | 39 | //Asynchronous task based 40 | var persons = await serviceClient.ListPersonsAsync(5); 41 | 42 | Assert.That(persons, Is.Not.Null); 43 | Assert.AreEqual(5, persons.Count()); 44 | 45 | //Asynchronous IAsyncResult based , awaiting with Task 46 | var person = await Task.Factory.FromAsync(serviceClient.BeginGetPerson, serviceClient.EndGetPerson, 1, null); 47 | Assert.That(person, Is.Not.Null); 48 | 49 | var nullCollection = await serviceClient.ListPersonsAsync(-1); 50 | Assert.IsNull(nullCollection); 51 | 52 | var nullObject = serviceClient.GetPerson(-1); 53 | Assert.IsNull(nullObject); 54 | } 55 | 56 | [Test] 57 | public void RequestGetsExceptionFromServer() 58 | { 59 | var clientFactory = new ServiceClientFactory(new SimpleClient(new ServiceFactory(this.resolver))); 60 | 61 | var serviceClient = clientFactory.CreateServiceClient(); 62 | 63 | //Synchronous 64 | var err = Assert.Catch(async () => await serviceClient.FailAsync()); 65 | Assert.IsNotNull(err); 66 | Assert.IsNotInstanceOf(err); 67 | 68 | //Asynchronous task based 69 | err = Assert.Catch(() => serviceClient.Fail()); 70 | Assert.IsNotNull(err); 71 | Assert.IsNotInstanceOf(err); 72 | 73 | //Asynchronous IAsyncResult based , awaiting with Task 74 | err = Assert.Catch(async () => await Task.Factory.FromAsync(serviceClient.BeginFail, serviceClient.EndFail, null)); 75 | Assert.IsNotNull(err); 76 | Assert.IsNotInstanceOf(err); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Services.InMemory/MyApp.Services.InMemory.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {494FF8D6-29D6-40F7-ADFD-E81589B36096} 8 | Library 9 | Properties 10 | MyApp.Services.InMemory 11 | MyApp.Services.InMemory 12 | v4.5 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | {cb34e9ef-7223-44a7-afb1-c0b89de4b26a} 49 | MyApp.Services 50 | 51 | 52 | 53 | 60 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/SwaggerUI/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Swagger UI 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 41 | 42 | 56 | 57 | 58 | 59 | 77 | 78 |
79 |   80 |
81 | 82 |
83 | 84 |
85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /source/ServiceProxy/Internal/ServiceClientInterceptor.cs: -------------------------------------------------------------------------------- 1 | using Castle.DynamicProxy; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace ServiceProxy.Internal 10 | { 11 | internal class ServiceClientInterceptor : IInterceptor 12 | { 13 | private readonly Type contractType; 14 | private readonly IClient client; 15 | private readonly Dictionary operationInterceptors; 16 | 17 | public ServiceClientInterceptor(Type contractType, IClient client) 18 | { 19 | this.contractType = contractType; 20 | this.client = client; 21 | this.operationInterceptors = contractType.GetMethods(BindingFlags.Instance | BindingFlags.Public) 22 | .ToDictionary(m => m.Name, this.CreateInvoker); 23 | } 24 | 25 | private OperationInterceptor CreateInvoker(MethodInfo method) 26 | { 27 | var parameters = method.GetParameters(); 28 | //supports IAsyncResult Begin/End, Task and synchronous 29 | 30 | //check if asynchronous 31 | if (typeof(IAsyncResult).IsAssignableFrom(method.ReturnType)) 32 | { 33 | //check if task 34 | if (typeof(Task).IsAssignableFrom(method.ReturnType)) 35 | { 36 | return new TaskOperationInterceptor(this.contractType, method, this.client); 37 | } 38 | else 39 | { 40 | //validate Begin APM signature 41 | if (parameters.Length >= 2 42 | && parameters[parameters.Length - 2].ParameterType == typeof(AsyncCallback) 43 | && parameters[parameters.Length - 1].ParameterType == typeof(object) 44 | && method.Name.StartsWith("Begin")) 45 | { 46 | return new BeginAsyncResultOperationInterceptor(this.contractType, method, this.client); 47 | } 48 | else 49 | { 50 | throw new InvalidOperationException(string.Format("Method {0}.{1} isn't compliant with IAsyncResult APM signature", this.contractType.FullName, method.Name)); 51 | } 52 | } 53 | } 54 | else 55 | { 56 | //check if is an End APM signature 57 | if (parameters.Length == 1 58 | && parameters[0].ParameterType == typeof(IAsyncResult) 59 | && method.Name.StartsWith("End")) 60 | { 61 | return new EndAsyncResultOperationInterceptor(this.contractType, method, this.client); 62 | } 63 | else 64 | { 65 | //synchronous invoker 66 | return new SynchronousOperationInterceptor(this.contractType, method, this.client); 67 | } 68 | } 69 | } 70 | 71 | public void Intercept(IInvocation invocation) 72 | { 73 | var operation = invocation.Method.Name; 74 | var interceptor = operationInterceptors[operation]; 75 | 76 | interceptor.Intercept(invocation); 77 | } 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /source/ServiceProxy/Internal/OperationInvokers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ServiceProxy.Internal 9 | { 10 | internal abstract class OperationInvoker 11 | { 12 | private readonly Func convertArgumentsFunc; 13 | 14 | public OperationInvoker(MethodInfo method) 15 | { 16 | this.convertArgumentsFunc = ReflectionUtils.BuildConvertArgumentsFunc(method); 17 | 18 | this.Name = method.Name; 19 | } 20 | 21 | public Task InvokeAsync(object serviceInstance, object[] arguments) 22 | { 23 | var args = this.convertArgumentsFunc(arguments); 24 | 25 | return this.DoInvokeAsync(serviceInstance, args); 26 | } 27 | 28 | public string Name { get; private set; } 29 | 30 | protected abstract Task DoInvokeAsync(object serviceInstance, object[] arguments); 31 | } 32 | 33 | internal class SynchronousOperationInvoker : OperationInvoker 34 | { 35 | private readonly Func operationFunc; 36 | 37 | public SynchronousOperationInvoker(MethodInfo method) 38 | : base(method) 39 | { 40 | this.operationFunc = ReflectionUtils.Sync.BuildOperationFunc(method); 41 | } 42 | 43 | protected override Task DoInvokeAsync(object serviceInstance, object[] arguments) 44 | { 45 | return Task.Run(() => this.operationFunc(serviceInstance, arguments)); 46 | } 47 | } 48 | 49 | internal class TaskBasedOperationInvoker : OperationInvoker 50 | { 51 | private readonly Func> operationFunc; 52 | 53 | public TaskBasedOperationInvoker(MethodInfo method) 54 | : base(method) 55 | { 56 | this.operationFunc = ReflectionUtils.Tasks.BuildOperationFunc(method); 57 | } 58 | 59 | protected override Task DoInvokeAsync(object serviceInstance, object[] arguments) 60 | { 61 | return this.operationFunc(serviceInstance, arguments); 62 | } 63 | } 64 | 65 | internal class AsyncResultBasedOperation : OperationInvoker 66 | { 67 | private readonly Func beginFunc; 68 | private readonly Func endFunc; 69 | 70 | public AsyncResultBasedOperation(MethodInfo method) 71 | : base(method) 72 | { 73 | this.beginFunc = ReflectionUtils.AsyncResult.BuildBeginOperationFunc(method); 74 | 75 | var endMethod = ReflectionUtils.AsyncResult.GetEndMethod(method); 76 | this.endFunc = ReflectionUtils.AsyncResult.BuildEndOperationFunc(endMethod); 77 | } 78 | 79 | protected override Task DoInvokeAsync(object serviceInstance, object[] arguments) 80 | { 81 | Func beginFunc = 82 | (args, asyncCallback, asyncState) => this.beginFunc(serviceInstance, args, asyncCallback, asyncState); 83 | 84 | Func endFunc = asyncResult => this.endFunc(serviceInstance, asyncResult); 85 | 86 | return Task.Factory.FromAsync(beginFunc, endFunc, arguments, null); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/RedisServer.cs: -------------------------------------------------------------------------------- 1 | using ServiceProxy; 2 | using StackExchange.Redis; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace ServiceProxy.Redis 11 | { 12 | public class RedisServer : IDisposable 13 | { 14 | private readonly RedisConnection connection; 15 | private readonly IServiceFactory serviceFactory; 16 | 17 | private readonly string serviceQueue; 18 | 19 | private long receiveState; 20 | private volatile Task receiveTask; 21 | 22 | public RedisServer(RedisConnection connection, string serviceQueue, IServiceFactory serviceFactory) 23 | { 24 | this.connection = connection; 25 | this.serviceFactory = serviceFactory; 26 | this.serviceQueue = serviceQueue; 27 | this.receiveState = 0; 28 | } 29 | 30 | public void Listen() 31 | { 32 | this.EnsureIsReceiving(); 33 | } 34 | 35 | private void EnsureIsReceiving() 36 | { 37 | if (Interlocked.CompareExchange(ref this.receiveState, 1, 0) == 0) 38 | { 39 | this.receiveTask = Task.Factory.StartNew(() => this.ReceiveRequests(), TaskCreationOptions.LongRunning).Unwrap(); 40 | } 41 | } 42 | 43 | private void EnsureIsNotReceiving() 44 | { 45 | if (Interlocked.CompareExchange(ref this.receiveState, 0, 1) == 1) 46 | { 47 | this.receiveTask.Wait(); 48 | } 49 | } 50 | 51 | private async Task ReceiveRequests() 52 | { 53 | int delayTimeout = 1; 54 | byte[] rawRequest; 55 | 56 | var redis = this.connection.GetClient(); 57 | 58 | while (Interlocked.Read(ref this.receiveState) == 1) 59 | { 60 | rawRequest = await redis.ListRightPopAsync(this.serviceQueue).IgnoreException(typeof(RedisException)); 61 | if (rawRequest == null) 62 | { 63 | await Task.Delay(delayTimeout); 64 | //increase timeout until delayMaxTimeout 65 | continue; 66 | } 67 | 68 | var redisRequestBytes = rawRequest; 69 | 70 | Task.Run(() => 71 | { 72 | var redisRequest = RedisRequest.FromBinary(redisRequestBytes); 73 | this.OnRequest(redis, redisRequest); 74 | }); 75 | } 76 | } 77 | 78 | private void OnRequest(IDatabase redis, RedisRequest redisRequest) 79 | { 80 | var service = this.serviceFactory.CreateService(redisRequest.Request.Service); 81 | 82 | service.Process(redisRequest.Request) 83 | .ContinueWith(t => 84 | { 85 | var response = t.Result; 86 | 87 | var redisResponse = new RedisResponse(redisRequest.Id, response); 88 | var redisResponseBytes = redisResponse.ToBinary(); 89 | 90 | redis.ListLeftPushAsync(redisRequest.ReceiveQueue, redisResponseBytes); 91 | }); 92 | } 93 | 94 | public void Dispose() 95 | { 96 | this.EnsureIsNotReceiving(); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.Serialization.Formatters.Binary; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace ServiceProxy.Zmq 10 | { 11 | static class ArrayExtensions 12 | { 13 | public static T[] Slice(this T[] data, int length) 14 | { 15 | return data.Slice(0, length); 16 | } 17 | 18 | public static T[] Slice(this T[] data, int index, int length) 19 | { 20 | T[] slice = new T[length]; 21 | Array.Copy(data, index, slice, 0, length); 22 | return slice; 23 | } 24 | 25 | public static byte[] ToBinary(T obj) 26 | { 27 | var formatter = new BinaryFormatter(); 28 | 29 | using (var stream = new MemoryStream()) 30 | { 31 | formatter.Serialize(stream, obj); 32 | return stream.GetBuffer(); 33 | } 34 | 35 | } 36 | 37 | public static T ToObject(byte[] objBytes) 38 | { 39 | var formatter = new BinaryFormatter(); 40 | 41 | using (var stream = new MemoryStream(objBytes)) 42 | { 43 | return (T)formatter.Deserialize(stream); 44 | } 45 | } 46 | } 47 | 48 | static class ZmqContextExtensions 49 | { 50 | public static Guid NewIdentity(this ZeroMQ.ZmqContext context) 51 | { 52 | Guid identity; 53 | while (true) 54 | { 55 | identity = Guid.NewGuid(); 56 | if (identity.ToByteArray()[0] != 0) 57 | { 58 | return identity; 59 | } 60 | } 61 | } 62 | 63 | public static ZeroMQ.ZmqSocket CreateNonBlockingReadonlySocket(this ZeroMQ.ZmqContext context, ZeroMQ.SocketType socketType, TimeSpan receiveTimeout) 64 | { 65 | var socket = CreateReadonlySocket(context, socketType); 66 | 67 | socket.ReceiveTimeout = receiveTimeout; 68 | 69 | return socket; 70 | } 71 | 72 | public static ZeroMQ.ZmqSocket CreateReadonlySocket(this ZeroMQ.ZmqContext context, ZeroMQ.SocketType socketType) 73 | { 74 | var socket = context.CreateSocket(socketType); 75 | 76 | socket.ReceiveHighWatermark = 0; 77 | socket.Linger = TimeSpan.FromMilliseconds(0); 78 | 79 | return socket; 80 | } 81 | 82 | public static ZeroMQ.ZmqSocket CreateWriteonlySocket(this ZeroMQ.ZmqContext context, ZeroMQ.SocketType socketType) 83 | { 84 | var socket = context.CreateSocket(socketType); 85 | 86 | socket.SendHighWatermark = 0; 87 | socket.Linger = TimeSpan.FromMilliseconds(0); 88 | 89 | return socket; 90 | } 91 | 92 | public static ZeroMQ.ZmqSocket CreateNonBlockingSocket(this ZeroMQ.ZmqContext context, ZeroMQ.SocketType socketType, TimeSpan timeout) 93 | { 94 | var socket = context.CreateSocket(socketType); 95 | 96 | socket.ReceiveTimeout = timeout; 97 | 98 | socket.ReceiveHighWatermark = 0; 99 | socket.SendHighWatermark = 0; 100 | 101 | socket.Linger = TimeSpan.FromMilliseconds(0); 102 | 103 | return socket; 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/Web.config: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /source/ServiceProxy.Tests/ClientTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using ServiceProxy.Tests.Stubs; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace ServiceProxy.Tests 12 | { 13 | [TestFixture] 14 | public class ClientTests 15 | { 16 | [SetUp] 17 | public void Setup() 18 | { 19 | 20 | } 21 | 22 | private void SetupClient(Mock clientMock, int? timeToReply = null) 23 | { 24 | clientMock.Setup(c => c.Request(It.IsAny(), It.IsAny())) 25 | .Returns( 26 | (RequestData request, CancellationToken token) => 27 | { 28 | Task responseTask; 29 | 30 | if (request.Operation == "Sum") 31 | { 32 | var data = new TestService().Sum((int)request.Arguments[0], (int)request.Arguments[1]); 33 | var response = new ResponseData(data); 34 | responseTask = Task.FromResult(response); 35 | } 36 | else if (request.Operation == "Concatenate") 37 | { 38 | var dataTask = new TestService().Concatenate(request.Arguments[0] as string[]); 39 | responseTask = dataTask.ContinueWith(t => new ResponseData(t.Result)); 40 | } 41 | else 42 | { 43 | throw new NotSupportedException("Only sum and Concatenate are supported in this mock"); 44 | } 45 | 46 | if (timeToReply.HasValue) 47 | { 48 | return Task.Delay(timeToReply.Value).ContinueWith(t => responseTask).Unwrap(); 49 | } 50 | else 51 | { 52 | return responseTask; 53 | } 54 | }); 55 | } 56 | 57 | [TearDown] 58 | public void TearDown() 59 | { 60 | 61 | } 62 | 63 | [Test] 64 | public void CanCreateClient() 65 | { 66 | var factory = new ServiceClientFactory(new Mock().Object); 67 | 68 | var serviceClient = factory.CreateServiceClient(); 69 | Assert.That(serviceClient, Is.Not.Null); 70 | } 71 | 72 | [Test] 73 | public void CanUseClientWithNonComplexTypes() 74 | { 75 | var clientMock = new Mock(); 76 | this.SetupClient(clientMock); 77 | 78 | var factory = new ServiceClientFactory(clientMock.Object); 79 | var serviceClient = factory.CreateServiceClient(); 80 | 81 | var sum = serviceClient.Sum(10, 5); 82 | Assert.That(sum, Is.EqualTo(15)); 83 | 84 | var concatenated = serviceClient.Concatenate("10", "01"); 85 | Assert.That(concatenated.Result, Is.EqualTo("1001")); 86 | 87 | } 88 | 89 | [Test] 90 | public void CanHandleTimeouts() 91 | { 92 | var clientMock = new Mock(); 93 | this.SetupClient(clientMock, 1000); //takes 100ms to reply 94 | 95 | var factory = new ServiceClientFactory(clientMock.Object); 96 | var serviceClient = factory.CreateServiceClient(50); //50ms timeout 97 | 98 | Assert.Throws(() => serviceClient.Sum(10, 5)); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /source/ServiceProxy.Tests/ServiceTests.cs: -------------------------------------------------------------------------------- 1 | using Moq; 2 | using NUnit.Framework; 3 | using ServiceProxy.Tests.Stubs; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace ServiceProxy.Tests 11 | { 12 | [TestFixture] 13 | public class ServiceTests 14 | { 15 | [SetUp] 16 | public void Setup() 17 | { 18 | 19 | } 20 | 21 | [TearDown] 22 | public void TearDown() 23 | { 24 | 25 | } 26 | 27 | [Test] 28 | public void CanCreateService() 29 | { 30 | var factory = new ServiceFactory(new Mock().Object); 31 | 32 | var service = factory.CreateService(); 33 | Assert.That(service, Is.Not.Null); 34 | } 35 | 36 | [TestCase(typeof(ITestService2), "ListPersons", new object[] { 3 })] 37 | [TestCase(typeof(ITestService2), "ListPersonsAsync", new object[] { 3 })] 38 | [TestCase(typeof(ITestService2), "BeginListPersons", new object[] { 3 })] 39 | public async void ProcessRequest_IEnumerable(Type serviceType, string operation, object[] arguments) 40 | { 41 | var response = await ProcessRequestInternal(serviceType, operation, arguments); 42 | 43 | Assert.IsNotNull(response.Data); 44 | Assert.IsTrue(typeof(IEnumerable).IsAssignableFrom(response.Data.GetType())); 45 | } 46 | 47 | [TestCase(typeof(ITestService2), "GetPerson", new object[] { 3 })] 48 | [TestCase(typeof(ITestService2), "GetPersonAsync", new object[] { 3 })] 49 | [TestCase(typeof(ITestService2), "BeginGetPerson", new object[] { 3 })] 50 | public async void ProcessRequest_ComplexType(Type serviceType, string operation, object[] arguments) 51 | { 52 | var responseData = await ProcessRequestInternal(serviceType, operation, arguments); 53 | 54 | Assert.IsNotNull(responseData.Data); 55 | Assert.IsInstanceOf(responseData.Data); 56 | } 57 | 58 | [TestCase(typeof(ITestService), "Sum", new object[] { 10, 5 })] 59 | [TestCase(typeof(ITestService), "Concatenate", new object[] { new string[] { "a", "b", "c" } })] 60 | [TestCase(typeof(ITestService), "GetDate", new object[0])] 61 | public async void ProcessRequest_SimpleArguments(Type serviceType, string operation, object[] arguments) 62 | { 63 | var responseData = await ProcessRequestInternal(serviceType, operation, arguments); 64 | 65 | Assert.IsNull(responseData.Exception); 66 | Assert.IsNotNull(responseData.Data); 67 | } 68 | 69 | [TestCase(typeof(ITestService2), "ListPersons", new object[] { -1 })] 70 | [TestCase(typeof(ITestService2), "ListPersonsAsync", new object[] { -1 })] 71 | [TestCase(typeof(ITestService2), "BeginListPersons", new object[] { -1 })] 72 | [TestCase(typeof(ITestService2), "GetPerson", new object[] { -1 })] 73 | [TestCase(typeof(ITestService2), "GetPersonAsync", new object[] { -1 })] 74 | [TestCase(typeof(ITestService2), "BeginGetPerson", new object[] { -1 })] 75 | public async void ProcessRequest_NullResults(Type serviceType, string operation, object[] arguments) 76 | { 77 | var response = await ProcessRequestInternal(serviceType, operation, arguments); 78 | 79 | Assert.IsNull(response.Exception); 80 | Assert.IsNull(response.Data); 81 | } 82 | 83 | private Task ProcessRequestInternal(Type serviceType, string operation, object[] arguments) 84 | { 85 | var factory = new ServiceFactory(new DependencyResolver()); 86 | var service = factory.CreateService(serviceType); 87 | 88 | var requestData = new RequestData(serviceType.FullName, operation, arguments); 89 | 90 | return service.Process(requestData); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.Services.InMemory/CatalogService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace MyApp.Services.InMemory 8 | { 9 | public class CatalogService : ICatalogService 10 | { 11 | 12 | public IEnumerable GetCatalogNames() 13 | { 14 | return Data.Catalogs.Keys; 15 | } 16 | 17 | public Task> GetCatalogNamesAsync() 18 | { 19 | return Task.FromResult(this.GetCatalogNames()); 20 | } 21 | 22 | public Catalog GetCatalog(string name) 23 | { 24 | return Data.Catalogs[name]; 25 | } 26 | 27 | public async Task GetCatalogAsync(string name) 28 | { 29 | await Task.Delay(5); //do some IO 30 | 31 | return Data.Catalogs[name]; 32 | } 33 | 34 | public ItemDetails GetItemDetails(string code) 35 | { 36 | return Data.Details[code]; 37 | } 38 | 39 | public Task GetItemDetailsAsync(string code) 40 | { 41 | return Task.FromResult(Data.Details[code]); 42 | } 43 | } 44 | 45 | static class Data 46 | { 47 | const int NumberOfItems = 500; 48 | static readonly string[] CatalogNames = new string[] { "Books", "Computers", "Tablets", "Consoles", "Games" }; 49 | 50 | public static readonly Dictionary Catalogs; 51 | 52 | //item code as key 53 | public static readonly Dictionary Details; 54 | 55 | static Data() 56 | { 57 | var itemsPerCatalog = NumberOfItems / CatalogNames.Length; 58 | 59 | var rnd = new Random(1337); 60 | 61 | var items = Enumerable.Range(0, NumberOfItems) 62 | .Select(i => 63 | new Item 64 | { 65 | Code = string.Format("i{0}", i), 66 | Description = string.Format("Description for item {0}", i), 67 | Price = rnd.Next(100) + 0.49M 68 | }).ToArray(); 69 | 70 | Details = items.Select(i => 71 | new ItemDetails 72 | { 73 | Item = i, 74 | DateTimeField = new DateTime(rnd.Next(1900, 2014), rnd.Next(1, 13), rnd.Next(1, 29)), 75 | GuidField = Guid.NewGuid(), 76 | IntField = rnd.Next(), 77 | LongField = long.MaxValue - rnd.Next(), 78 | NullableDoubleField = rnd.Next() % 2 == 0 ? (double?)rnd.NextDouble() : null, 79 | RandomTypeField = Enumerable.Range(0, rnd.Next(5)) 80 | .Select(r => 81 | new RandomType 82 | { 83 | CharField = (char)rnd.Next(256), 84 | IntArrayField = new int[] { rnd.Next(), rnd.Next(), rnd.Next() } 85 | }).ToArray() 86 | 87 | }).ToDictionary(d => d.Item.Code, d => d); 88 | 89 | Catalogs = Enumerable.Range(0, CatalogNames.Length) 90 | .Select(c => 91 | new Catalog 92 | { 93 | Name = CatalogNames[c], 94 | Items = Details.Values.Skip(c * itemsPerCatalog).Take(itemsPerCatalog).Select(d => d.Item).ToArray() 95 | }).ToDictionary(c => c.Name, c => c); 96 | } 97 | 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.WebAPI/SwaggerUI/lib/jquery.ba-bbq.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010 3 | * http://benalman.com/projects/jquery-bbq-plugin/ 4 | * 5 | * Copyright (c) 2010 "Cowboy" Ben Alman 6 | * Dual licensed under the MIT and GPL licenses. 7 | * http://benalman.com/about/license/ 8 | */ 9 | (function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this); -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/ServiceProxy.Redis.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {29C654BF-FCEE-4A8E-B72C-469C803A8BAA} 8 | Library 9 | Properties 10 | ServiceProxy.Redis 11 | ServiceProxy.Redis 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\StackExchange.Redis.1.0.247\lib\StackExchange.Redis.dll 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | {1ad4b97b-68d6-4ae0-b2a6-3c5b4d766030} 58 | ServiceProxy 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 69 | 70 | 71 | 72 | 79 | -------------------------------------------------------------------------------- /examples/MyApp/MyApp.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Services", "MyApp.Services\MyApp.Services.csproj", "{CB34E9EF-7223-44A7-AFB1-C0B89DE4B26A}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.WebAPI", "MyApp.WebAPI\MyApp.WebAPI.csproj", "{4601D984-A560-4A6D-8CBF-EB6ABD48072C}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Services.InMemory", "MyApp.Services.InMemory\MyApp.Services.InMemory.csproj", "{494FF8D6-29D6-40F7-ADFD-E81589B36096}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Backend", "Backend", "{189210D8-4F41-4125-A72B-11AA3BACEBB8}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Broker", "MyApp.Broker\MyApp.Broker.csproj", "{8CEACCED-2FA6-4CE6-8983-D87865DF344D}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyApp.Worker", "MyApp.Worker\MyApp.Worker.csproj", "{EFF5E964-646E-4291-B9F5-42A85FF9039E}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastructure", "{9FF34859-021B-431A-BAEA-87A3464F2267}" 17 | EndProject 18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Frontend", "Frontend", "{A625C772-BD98-4141-AE9E-C11097165033}" 19 | EndProject 20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{12631B50-4DD7-4245-B7DA-79E9ED912C77}" 21 | ProjectSection(SolutionItems) = preProject 22 | .nuget\NuGet.Config = .nuget\NuGet.Config 23 | .nuget\NuGet.exe = .nuget\NuGet.exe 24 | .nuget\NuGet.targets = .nuget\NuGet.targets 25 | EndProjectSection 26 | EndProject 27 | Global 28 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 29 | Debug|Any CPU = Debug|Any CPU 30 | Release|Any CPU = Release|Any CPU 31 | EndGlobalSection 32 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 33 | {CB34E9EF-7223-44A7-AFB1-C0B89DE4B26A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {CB34E9EF-7223-44A7-AFB1-C0B89DE4B26A}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {CB34E9EF-7223-44A7-AFB1-C0B89DE4B26A}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {CB34E9EF-7223-44A7-AFB1-C0B89DE4B26A}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {4601D984-A560-4A6D-8CBF-EB6ABD48072C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {4601D984-A560-4A6D-8CBF-EB6ABD48072C}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {4601D984-A560-4A6D-8CBF-EB6ABD48072C}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {4601D984-A560-4A6D-8CBF-EB6ABD48072C}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {494FF8D6-29D6-40F7-ADFD-E81589B36096}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {494FF8D6-29D6-40F7-ADFD-E81589B36096}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {494FF8D6-29D6-40F7-ADFD-E81589B36096}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {494FF8D6-29D6-40F7-ADFD-E81589B36096}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {8CEACCED-2FA6-4CE6-8983-D87865DF344D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {8CEACCED-2FA6-4CE6-8983-D87865DF344D}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {8CEACCED-2FA6-4CE6-8983-D87865DF344D}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {8CEACCED-2FA6-4CE6-8983-D87865DF344D}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {EFF5E964-646E-4291-B9F5-42A85FF9039E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {EFF5E964-646E-4291-B9F5-42A85FF9039E}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {EFF5E964-646E-4291-B9F5-42A85FF9039E}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {EFF5E964-646E-4291-B9F5-42A85FF9039E}.Release|Any CPU.Build.0 = Release|Any CPU 53 | EndGlobalSection 54 | GlobalSection(SolutionProperties) = preSolution 55 | HideSolutionNode = FALSE 56 | EndGlobalSection 57 | GlobalSection(NestedProjects) = preSolution 58 | {CB34E9EF-7223-44A7-AFB1-C0B89DE4B26A} = {9FF34859-021B-431A-BAEA-87A3464F2267} 59 | {4601D984-A560-4A6D-8CBF-EB6ABD48072C} = {A625C772-BD98-4141-AE9E-C11097165033} 60 | {494FF8D6-29D6-40F7-ADFD-E81589B36096} = {189210D8-4F41-4125-A72B-11AA3BACEBB8} 61 | {8CEACCED-2FA6-4CE6-8983-D87865DF344D} = {189210D8-4F41-4125-A72B-11AA3BACEBB8} 62 | {EFF5E964-646E-4291-B9F5-42A85FF9039E} = {189210D8-4F41-4125-A72B-11AA3BACEBB8} 63 | EndGlobalSection 64 | EndGlobal 65 | -------------------------------------------------------------------------------- /source/ServiceProxy.Zmq/ServiceProxy.Zmq.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {406A5869-5A75-489B-9F32-0E4F52A024E7} 8 | Library 9 | Properties 10 | ServiceProxy.Zmq 11 | ServiceProxy.Zmq 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\clrzmq.3.0.0-rc1\lib\net40\clrzmq.dll 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | {1ad4b97b-68d6-4ae0-b2a6-3c5b4d766030} 64 | ServiceProxy 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 75 | 76 | 77 | 78 | 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ServiceProxy 2 | ============ 3 | 4 | [![Join the chat at https://gitter.im/mfelicio/ServiceProxy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mfelicio/ServiceProxy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | ServiceProxy is a lightweight asynchronous proxy for .NET that allows you to use service contracts in a request/reply manner with your favorite messaging framework. 7 | 8 | ## How does it work? 9 | 10 | ### Client side 11 | 12 | On the client side ServiceProxy creates interface proxies for your service contracts, intercepts all service requests, converts them to well defined messages and sends them using a messaging framework. The created proxies are cached for the next requests. 13 | 14 | ### Server side 15 | 16 | On the server side ServiceProxy handles the messages received from your messaging framework, resolves/invokes the real service implementation and sends the response back. It uses the service locator pattern to resolve services, so you may use any IoC container. 17 | 18 | The first time a service call is made for a given contract, ServiceProxy generates, compiles and caches delegates that invoke your service operations and integrate seamlessly with the ServiceProxy request/reply interface. This means it is as fast as a direct method call to your services, since after the first execution no reflection will be done. 19 | 20 | ServiceProxy doesn't require any configuration. 21 | 22 | Want to know more? Read [how ServiceProxy core components work][serviceproxy-core-readme]. 23 | 24 | ## Getting started 25 | 26 | The quickest way to get started with ServiceProxy is by using the [NuGet package][serviceproxy-nuget]. You may also use one of the bundled request/reply messaging frameworks available in the source code [ServiceProxy.Redis][serviceproxy.redis-github] and [ServiceProxy.Zmq][serviceproxy.zmq-github]. 27 | 28 | The latest stable version is 1.0.1. For more information, visit the [Release notes][serviceproxy-releasenotes-github] page. 29 | 30 | ## Why use ServiceProxy 31 | 32 | Using ServiceProxy your code can be decoupled from the messaging framework you're using and from the ServiceProxy framework itself. If your code uses Dependency Injection and you use a modern IoC container, you can have your code depend on your service interfaces and have the IoC container create the proxies using the ServiceClientFactory. It doesn't intend to replace your messaging framework since ServiceProxy by itself has no messaging capabilities. It just has a simple and asynchronous request/reply model that is supposed to integrate seamlessly with any messaging framework. However, if you don't use one already you can give [ServiceProxy.Redis][serviceproxy.redis-github] and [ServiceProxy.Zmq][serviceproxy.zmq-github] a try. 33 | 34 | ## Contributing 35 | 36 | You can contribute by creating a ServiceProxy.[YourFavoriteMessageBus] and submit your code to github. Make sure to make a reference to this project and I'll make sure it is listed here as well. 37 | 38 | ### Examples 39 | 40 | A complete WebAPI example using a service layer can be found [here][serviceproxy-examples-myapp]. If you would like to contribute with examples let me know. 41 | 42 | ### Issues 43 | 44 | If you find any issues please post them on the [issues][serviceproxy-issues-github] page. 45 | 46 | ## Dependencies 47 | 48 | ServiceProxy uses [Castle.Core][castle.core-github] DynamicProxy internally to generate client side interface proxies. 49 | 50 | ## License 51 | 52 | ServiceProxy is licensed under the [MIT][serviceproxy-license] license. 53 | 54 | [serviceproxy-nuget]: http://packages.nuget.org/Packages/ServiceProxy 55 | [serviceproxy.redis-github]: https://github.com/mfelicio/ServiceProxy/tree/master/source/ServiceProxy.Redis 56 | [serviceproxy.zmq-github]: https://github.com/mfelicio/ServiceProxy/tree/master/source/ServiceProxy.Zmq 57 | [serviceproxy-issues-github]: https://github.com/mfelicio/ServiceProxy/issues 58 | [serviceproxy-releasenotes-github]: https://github.com/mfelicio/ServiceProxy/blob/master/CHANGELOG.md 59 | [castle.core-github]: https://github.com/castleproject/Core 60 | [serviceproxy-license]: http://opensource.org/licenses/mit-license.php 61 | [serviceproxy-examples-myapp]: https://github.com/mfelicio/ServiceProxy/tree/master/examples/MyApp 62 | [serviceproxy-core-readme]: https://github.com/mfelicio/ServiceProxy/tree/master/source/ServiceProxy 63 | -------------------------------------------------------------------------------- /source/ServiceProxy/ServiceProxy.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1AD4B97B-68D6-4AE0-B2A6-3C5B4D766030} 8 | Library 9 | Properties 10 | ServiceProxy 11 | ServiceProxy 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Castle.Core.3.2.2\lib\net45\Castle.Core.dll 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 73 | 74 | 75 | 76 | 83 | -------------------------------------------------------------------------------- /source/ServiceProxy.Tests/ServiceProxy.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {C3061055-2FA5-4A0F-9B65-86C8BAA8E238} 8 | Library 9 | Properties 10 | ServiceProxy.Tests 11 | ServiceProxy.Tests 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Moq.4.2.1312.1622\lib\net40\Moq.dll 37 | 38 | 39 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | {1ad4b97b-68d6-4ae0-b2a6-3c5b4d766030} 64 | ServiceProxy 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 75 | 76 | 77 | 78 | 85 | -------------------------------------------------------------------------------- /examples/Redis/Client/Client.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B6B77D09-AB39-472B-A0B2-12B153391057} 8 | Exe 9 | Properties 10 | Client 11 | Client 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\Castle.Core.3.2.2\lib\net45\Castle.Core.dll 39 | 40 | 41 | ..\packages\ServiceProxy.1.0.1\lib\net45\ServiceProxy.dll 42 | 43 | 44 | False 45 | ..\packages\ServiceProxy.Redis.1.1.0\lib\net45\ServiceProxy.Redis.dll 46 | 47 | 48 | False 49 | ..\packages\StackExchange.Redis.1.0.247\lib\StackExchange.Redis.dll 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {e516d255-31f9-4ebe-a60c-de755b935acd} 70 | ServiceContracts 71 | 72 | 73 | 74 | 75 | 76 | 77 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 78 | 79 | 80 | 81 | 88 | -------------------------------------------------------------------------------- /examples/Redis/Server/Server.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {6EFA3BF8-D1B0-407B-A3E9-6A35D7AC884B} 8 | Exe 9 | Properties 10 | Server 11 | Server 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\Castle.Core.3.2.2\lib\net45\Castle.Core.dll 39 | 40 | 41 | ..\packages\ServiceProxy.1.0.1\lib\net45\ServiceProxy.dll 42 | 43 | 44 | False 45 | ..\packages\ServiceProxy.Redis.1.1.0\lib\net45\ServiceProxy.Redis.dll 46 | 47 | 48 | False 49 | ..\packages\StackExchange.Redis.1.0.247\lib\StackExchange.Redis.dll 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | {e516d255-31f9-4ebe-a60c-de755b935acd} 71 | ServiceContracts 72 | 73 | 74 | 75 | 76 | 77 | 78 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 79 | 80 | 81 | 82 | 89 | -------------------------------------------------------------------------------- /source/ServiceProxy/README.md: -------------------------------------------------------------------------------- 1 | ServiceProxy 2 | ============ 3 | 4 | This page contains a brief explanation of how ServiceProxy core components work. 5 | 6 | ## Client side 7 | 8 | On the client side there are only two interfaces that you must deal with: IClient and IServiceClientFactory. 9 | 10 | The IClient interface represents your messaging client adapter, see interface below. 11 | 12 | ```c# 13 | public interface IClient 14 | { 15 | Task Request(RequestData request, CancellationToken token); 16 | } 17 | ``` 18 | 19 | For each request sent it returns a task that will complete when the response result is received. The RequestData object contains the required information to do a remote service call: service name, operation name and arguments. 20 | 21 | ```c# 22 | [Serializable] 23 | public class RequestData 24 | { 25 | public RequestData(string service, string operation, object[] arguments) 26 | { 27 | this.Service = service; 28 | this.Operation = operation; 29 | this.Arguments = arguments; 30 | } 31 | 32 | public string Service { get; private set; } 33 | public string Operation { get; private set; } 34 | public object[] Arguments { get; private set; } 35 | } 36 | ``` 37 | 38 | To create service proxies you use the IServiceClientFactory. The actual implementation generates proxies using Castle.Core.DynamicProxy, intercepts all calls and uses an IClient instance to make requests / return responses. You can also specify timeouts when creating proxies, that will be used for all requests made by that proxy. 39 | 40 | ```c# 41 | public interface IServiceClientFactory 42 | { 43 | TService CreateServiceClient(int? timeout = null) where TService : class; 44 | object CreateServiceClient(Type serviceType, int? timeout = null); 45 | } 46 | ``` 47 | 48 | ## Server side 49 | 50 | On the server side the interfaces you need to use are the IService and IServiceFactory. 51 | 52 | ```c# 53 | public interface IServiceFactory 54 | { 55 | IService CreateService() where TService : class; 56 | 57 | IService CreateService(string serviceName); 58 | 59 | IService CreateService(Type serviceType); 60 | } 61 | 62 | public interface IService 63 | { 64 | Task Process(RequestData requestData); 65 | } 66 | ``` 67 | 68 | The IService interface represents a proxy to your actual service instance. You can use whatever mechanism your messaging frameworks provides you to handle the messages you sent from the IClient instance. Then you can use the IServiceFactory to create IService instances that will process the requests using the data received from your message handler. The ResponseData object contains the required information to send response results using your messaging framework to the IClient instance that originated the request. 69 | 70 | ```c# 71 | [Serializable] 72 | public class ResponseData 73 | { 74 | public ResponseData(object data) 75 | { 76 | this.Data = data; 77 | this.Exception = null; 78 | } 79 | 80 | public ResponseData(Exception error) 81 | { 82 | this.Data = null; 83 | this.Exception = error; 84 | } 85 | 86 | public object Data { get; private set; } 87 | public Exception Exception { get; private set; } 88 | } 89 | ``` 90 | When the IServiceFactory creates an IService for a given service Type, it will dynamically generate, compile and cache delegates that invoke methods on your service instances. These delegates don't use reflection, so it is as fast as having a method that checks what operation it has to call based on the RequestData and directly invokes your service methods. 91 | 92 | The IServiceFactory doesn't know how to create your service instances, and won't use reflection using the Activator class. Instead it relies on the Service Locator pattern using the IDependencyResolver interface, which lets you decide how your services will be created. The recommended approach will be to create an adapter for your IoC container and Resolve your services. 93 | 94 | ```c# 95 | public interface IDependencyResolver 96 | { 97 | object Resolve(Type type); 98 | } 99 | ``` 100 | 101 | You don't have to implement the IServiceClientFactory nor the IServiceFactory nor IService's. ServiceProxy already has implementations for them, that's the core for this project. However you should always depend on these interfaces and not the actual implementations, so that the core components of ServiceProxy can evolve / change and keep your code compatible with it. 102 | 103 | The implementation of ServiceProxy components was carefully done having performance in mind. ServiceProxy aims to be a very lightweight proxy, so most internal components are created once, cached and retrieved using O(1) calls. -------------------------------------------------------------------------------- /source/ServiceProxy.Redis.Tests/ServiceProxy.Redis.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EA22ED16-B163-4777-8A04-F041BDB3E2A7} 8 | Library 9 | Properties 10 | ServiceProxy.Redis.Tests 11 | ServiceProxy.Redis.Tests 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Moq.4.2.1312.1622\lib\net40\Moq.dll 37 | 38 | 39 | ..\packages\NUnit.2.6.3\lib\nunit.framework.dll 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | 62 | 63 | {29c654bf-fcee-4a8e-b72c-469c803a8baa} 64 | ServiceProxy.Redis 65 | 66 | 67 | {c3061055-2fa5-4a0f-9b65-86c8baa8e238} 68 | ServiceProxy.Tests 69 | 70 | 71 | {1ad4b97b-68d6-4ae0-b2a6-3c5b4d766030} 72 | ServiceProxy 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 83 | 84 | 85 | 86 | 93 | -------------------------------------------------------------------------------- /source/ServiceProxy.Redis/RedisClient.cs: -------------------------------------------------------------------------------- 1 | using ServiceProxy; 2 | using StackExchange.Redis; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace ServiceProxy.Redis 12 | { 13 | public class RedisClient : IClient, IDisposable 14 | { 15 | private readonly RedisConnection connection; 16 | 17 | private readonly string receiveQueue; 18 | private readonly string sendQueue; 19 | 20 | private readonly ConcurrentDictionary> requestCallbacks; 21 | 22 | private long nextId; 23 | private long receiveState; 24 | private volatile Task receiveTask; 25 | 26 | public RedisClient(RedisConnection connection, string receiveQueue, string sendQueue) 27 | { 28 | this.connection = connection; 29 | this.receiveQueue = receiveQueue; 30 | this.sendQueue = sendQueue; 31 | this.nextId = 0; 32 | this.receiveState = 0; 33 | this.requestCallbacks = new ConcurrentDictionary>(); 34 | } 35 | 36 | private string NextId() 37 | { 38 | return Interlocked.Increment(ref this.nextId).ToString(); 39 | } 40 | 41 | public Task Request(RequestData request, CancellationToken token) 42 | { 43 | this.EnsureIsReceiving(); 44 | 45 | var requestId = this.NextId(); 46 | 47 | var redisRequest = new RedisRequest(this.receiveQueue, requestId, request); 48 | var redisRequestBytes = redisRequest.ToBinary(); 49 | 50 | var redis = this.connection.GetClient(); 51 | var lpushTask = redis.ListLeftPushAsync(sendQueue, redisRequestBytes); 52 | 53 | var callback = new TaskCompletionSource(); 54 | this.requestCallbacks[requestId] = callback; 55 | 56 | if (token != CancellationToken.None) 57 | { 58 | token.Register(() => 59 | { 60 | this.OnRequestCancelled(requestId); 61 | }); 62 | } 63 | 64 | lpushTask.ContinueWith(t => 65 | { 66 | if (lpushTask.Exception != null) 67 | { 68 | this.OnRequestError(requestId, lpushTask.Exception.InnerException); 69 | } 70 | }); 71 | 72 | return callback.Task; 73 | } 74 | 75 | private void EnsureIsReceiving() 76 | { 77 | if (Interlocked.CompareExchange(ref this.receiveState, 1, 0) == 0) 78 | { 79 | this.receiveTask = Task.Factory.StartNew(() => this.Receive(), TaskCreationOptions.LongRunning).Unwrap(); 80 | } 81 | } 82 | 83 | private void EnsureIsNotReceiving() 84 | { 85 | if (Interlocked.CompareExchange(ref this.receiveState, 0, 1) == 1) 86 | { 87 | this.receiveTask.Wait(); 88 | } 89 | } 90 | 91 | private async Task Receive() 92 | { 93 | int delayTimeout = 1; 94 | byte[] rawResponse; 95 | 96 | var redis = this.connection.GetClient(); 97 | 98 | while (Interlocked.Read(ref this.receiveState) == 1) 99 | { 100 | rawResponse = await redis.ListRightPopAsync(receiveQueue).IgnoreException(typeof(RedisException)); 101 | if (rawResponse == null) 102 | { 103 | await Task.Delay(delayTimeout); 104 | //maybe increase delayTimeout a little bit? 105 | continue; 106 | } 107 | 108 | var redisResponseBytes = rawResponse; 109 | 110 | Task.Run(() => 111 | { 112 | var redisResponse = RedisResponse.FromBinary(redisResponseBytes); 113 | this.OnResponse(redisResponse); 114 | }); 115 | } 116 | 117 | } 118 | 119 | private void OnResponse(RedisResponse redisResponse) 120 | { 121 | TaskCompletionSource callback; 122 | if (this.requestCallbacks.TryRemove(redisResponse.RequestId, out callback)) 123 | { 124 | callback.SetResult(redisResponse.Response); 125 | } 126 | } 127 | 128 | private void OnRequestError(string requestId, Exception exception) 129 | { 130 | TaskCompletionSource callback; 131 | if (this.requestCallbacks.TryRemove(requestId, out callback)) 132 | { 133 | callback.TrySetException(exception); 134 | } 135 | } 136 | 137 | private void OnRequestCancelled(string requestId) 138 | { 139 | TaskCompletionSource _; 140 | this.requestCallbacks.TryRemove(requestId, out _); 141 | } 142 | 143 | public void Dispose() 144 | { 145 | this.EnsureIsNotReceiving(); 146 | this.requestCallbacks.Clear(); 147 | } 148 | } 149 | } 150 | --------------------------------------------------------------------------------