使用接口的方式调用远程服务 ------ 利用动态调用服务,实现.net下类似Dubbo的玩法。
分布式微服务现在成为了很多公司架构首先项,据我了解,很多java公司架构都是 Maven+Dubbo+Zookeeper基础上扩展的。
Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
关于更多Dubbo更多资料,可以查看Dubbo官方文档。值得一提的是,Dubbo官方文档也是一份非常好的分布式学习资料。
那么.net下能不能类似dubbo那样玩呢?目前好像没有找到.net下类似的实现。感觉很多公司应该有自己类似实现,但是没有开源出来吧。
我这里先做一个类似的基于接口的远程调用的实现,项目的服务实现使用WCF,IOC注入使用Autofac。
一,解决方案整体设计
(一)Cn.Code.Demo
如上图,Cn.Code.Demo 解决方案包含了所有的项目。
如上图:1 Cn.Code.Common 是项目一些公共方法的实现。
2 Cn.Code.Core 是项目所有的对外接口,此项目只包含接口。
3 Cn.Code.Demo 是一个MVC项目,用于测试我们的接口调用。
4 Cn.Code.FirstService 第一个服务实现,实现了Cn.Code.Core 部分接口。
5 Cn.Code.SecondService 第二个服务实现,实现了Cn.Code.Core 部分接口。
(二)Cn.Code.FirstService
此解决方案只包含 Cn.Code.Core 和Cn.Code.FirstService 。
(三)Cn.Code.SecondService
此解决方案只包含 Cn.Code.Core 和Cn.Code.SecondService 。
二,接口层 --Cn.Code.Core
接口层只包含如下2个接口,这里我使用WCF进行测试,所以需要添加System.ServiceModel 模块引用。
IFirstService 接口如下:
[ServiceContract]
public interface IFirstService
{
[OperationContract]
string GetData();
}
ISecondService接口如下:
[ServiceContract]
public interface ISecondService
{
[OperationContract]
string GetData();
}
三,服务实现 --Cn.Code.FirstService 和Cn.Code.SecondService
为了方便测试,这里的服务实现都非常简单。
public class FirstService :IFirstService
{
public string GetData()
{
return string.Format("您调用了 FirstService !");
} }
public class SecondService :ISecondService
{
public string GetData()
{
return string.Format("您调用了 SecondService !");
}
}
四,公共方法实现 --Cn.Code.Common
首先是WCF动态调用的构建工厂。
/// <summary>
/// Wcf动态调用构建
/// </summary>
public class WcfInvokeFactory
{
#region WCF服务工厂
public static T GetService<T>(string url)
{
return GetService<T>(url, "basicHttpBinding");
} public static T GetService<T>(string url, string bing)
{
try
{
if (string.IsNullOrEmpty(url)) throw new NotSupportedException("This url is not Null or Empty!");
EndpointAddress address = new EndpointAddress(url);
Binding binding = CreateBinding(bing);
ChannelFactory<T> factory = new ChannelFactory<T>(binding, address);
return factory.CreateChannel();
}
catch (Exception ex)
{
throw new Exception("创建服务工厂出现异常.");
}
}
#endregion #region 创建传输协议
/// <summary>
/// 创建传输协议
/// </summary>
/// <param name="binding">传输协议名称</param>
/// <returns></returns>
private static Binding CreateBinding(string binding)
{
Binding bindinginstance = null;
if (binding.ToLower() == "basichttpbinding")
{
BasicHttpBinding ws = new BasicHttpBinding();
ws.MaxBufferSize = ;
ws.MaxBufferPoolSize = ;
ws.MaxReceivedMessageSize = ;
ws.ReaderQuotas.MaxStringContentLength = ;
ws.CloseTimeout = new TimeSpan(, , );
ws.OpenTimeout = new TimeSpan(, , );
ws.ReceiveTimeout = new TimeSpan(, , );
ws.SendTimeout = new TimeSpan(, , ); bindinginstance = ws;
}
else if (binding.ToLower() == "nettcpbinding")
{
NetTcpBinding ws = new NetTcpBinding();
ws.MaxReceivedMessageSize = ;
ws.Security.Mode = SecurityMode.None;
bindinginstance = ws;
}
else if (binding.ToLower() == "wshttpbinding")
{
WSHttpBinding ws = new WSHttpBinding(SecurityMode.None);
ws.MaxReceivedMessageSize = ;
ws.Security.Message.ClientCredentialType = System.ServiceModel.MessageCredentialType.Windows;
ws.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;
bindinginstance = ws;
}
return bindinginstance; }
#endregion
}
WcfInvokeFactory
其次是扩展Autofac一个注册接口的方法。
/// <summary>
/// Autofac 扩展注入方法
/// </summary>
public static class RegistExtensions
{
/// <summary>
///
/// </summary>
/// <typeparam name="T">需要注入的接口类型</typeparam>
/// <param name="builder"></param>
/// <param name="url">接口服务调用URL</param>
/// <returns></returns>
public static IRegistrationBuilder<T, SimpleActivatorData, SingleRegistrationStyle> RegisterService<T>(this ContainerBuilder builder, string url)
{
return builder.Register(c => WcfInvokeFactory.GetService<T>(url)).As<T>();
}
}
RegistExtensions
五,MVC项目测试 --Cn.Code.Demo
首先运行2个解决方案Cn.Code.FirstService与Cn.Code.SecondService,得到2个服务地址,将地址配置到项目的web.config中。
<add key="FirstService" value="http://localhost:9970/FirstService.svc"/>
<add key="SecondService" value="http://localhost:10014/SecondService.svc"/>
其次在全局文件Global.asax中,利用自定义Autofac注册扩展,分别注入不同的服务地址。
using Autofac;
using Autofac.Integration.Mvc; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Web.Security;
using System.Web.SessionState;
using System.Configuration; using Cn.Code.Core;
using Cn.Code.Common; namespace Cn.Code.Demo
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
var builder = new ContainerBuilder();
SetupResolveRules(builder);
builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly()).AsImplementedInterfaces();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); } private void SetupResolveRules(ContainerBuilder builder)
{
//利用自定义注册扩展,分别注入不同的服务地址
builder.RegisterService<IFirstService>(ConfigurationManager.AppSettings["FirstService"]);
builder.RegisterService<ISecondService>(ConfigurationManager.AppSettings["SecondService"]);
}
}
}
Global.asax
接下来就是调用我们的接口了。
using Cn.Code.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace Cn.Code.Demo.Controllers
{
public class HomeController : Controller
{
private IFirstService _iFirstService;
private ISecondService _iSecondService;
public HomeController() { }
public HomeController(IFirstService iFirstService, ISecondService iSecondService)
{
this._iFirstService = iFirstService;
this._iSecondService = iSecondService;
}
public ActionResult Index()
{
//第一个接口
ViewBag.FirstText = _iFirstService.GetData();
//第二个接口
ViewBag.SecondText = _iSecondService.GetData();
return View();
}
}
}
HomeController
视图页面输出结果。
@{
ViewBag.Title = "Home Page";
}
<div class="row">
@ViewBag.FirstText
<br />
@ViewBag.SecondText
</div>
调用成功。
五,总结
这样的话,我们的远程调用服务接口就和平时正常调用使用项目内接口方法一样了。同时这样拆分,可以将不同的服务注册到不同的节点。这个节点也可以是一个集群。
当然,这里只是个测试小demo,后续应该结合Zookeeper或者其他的分布式服务框架,实现均衡负载的管理。
注:代码比较low,望见谅。代码下载地址Cn.Code.Demo.zip
使用接口的方式调用远程服务 ------ 利用动态调用服务,实现.net下类似Dubbo的玩法。的更多相关文章
- MyBatis进阶--接口代理方式实现Dao 和动态SQL
MyBatis接口代理方式实现Dao层 接口代理方式-实现规则 传统方式实现Dao层,我们既要写接口.还要写实现类.而MyBatis框架可以帮助我们省略写Dao层接口实现类的步骤.程序员只需要编写接口 ...
- SOA 下实现分布式 调用 cxf+ webService +动态调用
近期项目间隙 自学了 webservice 一下 是我写的 一个demo 首先我们在web.xml 里配置如下 <servlet> <servlet-name>CXFS ...
- Spring学习总结(8)-接口多个实现类的动态调用
需求描述:当一个接口有2个以上的实现类时,调用方需要根据参数选择只其中一个实现类 Spring版本:5.1.8.RELEASE 1. 接口和实现类 /** * 接口 */ public interfa ...
- C# .NET 动态调用webservice的三种方式
转载自 百度文库 http://wenku.baidu.com/link?url=Q2q50wohf5W6UX44zqotXFEe_XOMaib4UtI3BigaNwipOHKNETloMF4ax4W ...
- .net WebServer示例及调用(接口WSDL动态调用 JAVA)
新建.asmx页面 using System; using System.Collections.Generic; using System.Linq; using System.Web; using ...
- c# 动态调用.net编写的webservices接口
创建类WebServiceHelper: public class WebServiceHelper { #region 动态调用WebService动态调用地址 /// < summary&g ...
- 调用webservice服务(通过反射的方式动态调用)
调用 ";//系统类别 var jkxlh = "";//接口序列号 var jkid = "68W05";//接口id string WriteXm ...
- Web Service学习笔记:动态调用WebService
原文:Web Service学习笔记:动态调用WebService 多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我 ...
- Delphi DLL的创建、静态及动态调用
转载:http://blog.csdn.net/welcome000yy/article/details/7905463 结合这篇博客:http://www.cnblogs.com/xumenger/ ...
随机推荐
- mysql生成随机测试数据
一个demo: CREATE TABLE dept_InnoDB( deptno MEDIUMINT NOT NULL DEFAULT 0 , dname VARCHAR(20) NOT NULL ...
- Windows下重启指定名称的服务
// 重启指定服务 void CPSSDPrinterCtrlPlug::RestartService(const wchar_t* nswServiceName) { SC_HANDLE schSC ...
- 创建多模块maven项目
有两种方式: 1,new -->maven project-->maven-archetype-quickstart 建完多个独立的project后,手动修改pom文件的packing类型 ...
- java基础知识(二)
java的布局管理: borderLayout:则将板块分为东西南北中五个方向,每添加一个组件就要指定组件摆放的方位,放置在东西南北四个方向的组件将贴边放置.当拉大Frame的时候,处在center( ...
- bootstrap完整导航栏
效果图: 代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- 汉得第二次考核答案整理(通信,IO,文件等)
1, (8 分 ) 使用程序从网上下载 pdf, 网址为http://files.saas.hand-china.com/java/target.pdf,保存在本地,编程时使用带缓冲的读写,将需要保证 ...
- appium 并发测试
Android并发测试 Appium提供了在一台设备上启动多个Android会话的方案,而这个方案需要你输入不同的指令来启动多个Appium服务来实现. 启动多个Android会话的重要指令包括: - ...
- Jmeter命令行运行实例讲解
1. 简介 使用非 GUI 模式,即命令行模式运行 JMeter 测试脚本能够大大缩减所需要的系统资 本文介绍windows下以命令行模式运行的方法. 1.1. 命令介绍 jmeter -n -t & ...
- 你需要知道的九大排序算法【Python实现】之冒泡排序
二.冒泡排序 基本思想:它的思路很有特点循环,两两向后比较.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换,也就是说该数 ...
- Javascript:数组和字符串的相互转化
中午吃饭的时候,和室友讨论前端的问题,然后一个有趣的问题被抛出来: javascript用什么方法可以把“hello world”位置反转输出,即输出:"dlrow olleh"? ...