使用接口的方式调用远程服务 ------ 利用动态调用服务,实现.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/ ...
随机推荐
- hdu 4535 吉哥系列故事——礼尚往来
http://acm.hdu.edu.cn/showproblem.php?pid=4535 错排公式:a[i]=(i-1)*(a[i-2]+a[i-1]): #include <cstdio& ...
- [LeetCode 112 113] - 路径和I & II (Path Sum I & II)
问题 给出一棵二叉树及一个和值,检查该树是否存在一条根到叶子的路径,该路径经过的所有节点值的和等于给出的和值. 例如, 给出以下二叉树及和值22: 5 / \ 4 8 ...
- WPF 自己动手来做安装卸载程序
原文:WPF 自己动手来做安装卸载程序 前言 说起安装程序,这也许是大家比较遗忘的部分,那么做C/S是小伙伴们,难道你们的程序真的不需要一个炫酷的安装程序么? 声明在先 本文旨在教大家以自己的方式实现 ...
- poj3237 Tree
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- my dup2
#include <fcntl.h>#include <stdio.h>#include <unistd.h> int mydup(int i_OldFd, int ...
- [LeetCode] 128. Longest Consecutive Sequence 解题思路
Given an unsorted array of integers, find the length of the longest consecutive elements sequence. F ...
- windows 自动安装
msiexec
- MyEclipse8.6下的svn插件安装
myeclipse8.6的svn插件安装 下载site-1.6.18.zip 在myeclipse8.6的MyEclipse8.6的安装目录D:/install/MyEclipse8.6/Genuit ...
- MAC安装SVNServer
MAC已经自带了SVN,所以,直接使用就好 1.创建svn repository svnadmin create /path/svn/pro //仓库位置,svn是svn的目录,pro是一个版本库的 ...
- lesson3:使用java代码的方式对不能识别的协议进行压力测试
在我们的实际环境中,我们所使用的协议肯定不只是http的方式,对于rpc等调用协议,目前jmeter没有相应的sampler支持,这时就需要通过引入我们自己写的jar包的方式来解决这个问题.例如:当我 ...