elastic communication是基於c#開發支援.net和mono的通訊元件(簡稱EC),EC的主要目的簡化mono和.net下的通訊開發難度,通過EC可以非常快速地開發基於mono和.net的通訊互動應用。EC抽取的基礎的通訊協議預設支援protobuf,msgpack的資料物件進行通訊互動,開發者不可以根據自己的制要制訂更多的序列化方式支援;EC不緊緊支援簡單的對像傳輸,還提供了控制器,方法控制器和更方便的遠端介面呼叫功能。
以下是ES希望實現的最終目標
藉助於Xamarin實現不同移動端的實現,由於這一塊個人工作原因還沒細化實現,通過開源相關程式碼可以讓感興趣的人更好進一步去完成相關功能。
功能簡介
EC實現通訊功能是非常方便的事情,下面通訊簡單的幾種場景來介紹一下EC在通訊上的應用。
HelloWord
- 服務端
namespace HelloWord.Server { [Controller] public class Program { static void Main(string[] args) { ECServer.Open(); System.Threading.Thread.Sleep(-1); } public string HelloWord(ISession session,Hello e) { return string.Format("hello {0} [say time:{1}]", e.Name, DateTime.Now); } } [MessageID(0x1)] [ProtoContract] public class Hello { [ProtoMember(1)] public string Name { get; set; } } }
- 客戶端
private EC.ProtoSyncClient mClient = new ProtoSyncClient("127.0.0.1"); mClient.Send<string>(new Hello { Name=textBox1.Text })
遠端方法訪問
EC支援遠端方法呼叫,如果用過wcf那對這功能感覺應該不會陌生,而EC也是通過介面的方式來定義遠端呼叫行為;wcf同一方法過載需要重新定義名稱,而ec則支援同一方法多個過載版本。為了滿足更復雜的需要,EC的遠端呼叫同樣支援out和ref引數。
- 介面定義
namespace Remoting.Service { public interface IUserService { User Register(string name, string email); } }
- 服務端
[SOAService(typeof(Service.IUserService))] class Program : IUserService { static void Main(string[] args) { ECServer.Open(); System.Threading.Thread.Sleep(-1); } public Service.User Register(string name, string email) { User user = new User(); user.EMail = email; user.Name = name; user.CreateTime = DateTime.Now; return user; } }
- 客戶端
public partial class Form1 : Form { public Form1() { InitializeComponent(); } private ProtoClient mClient = new ProtoClient("192.168.7.111"); private IUserService UserService; private void Form1_Load(object sender, EventArgs e) { UserService = mClient.CreateInstance<IUserService>(); } private void cmdRegister_Click(object sender, EventArgs e) { User user= UserService.Register(txtName.Text, txtEMail.Text); txtCreateTime.Text = user.CreateTime.ToString(); } }
資料訪問示例
資料訪問應該是最常見的一種應用場,以下是定義一個簡單的資料查詢示例。
- 服務端
[EC.Controller] public class Program { static void Main(string[] args) { DBContext.SetConnectionDriver<SqliteDriver>(DB.DB1); DBContext.SetConnectionString(DB.DB1, "Data Source=northwindEF.db;Pooling=true;FailIfMissing=false;"); ECServer.Open(); System.Threading.Thread.Sleep(-1); } public IList<Employee> OnEmployeeSearch(ISession session, EmployeeSearch e) { return new Expression().List<Models.Employees, Employee>(); } public IList<Customer> OnCustomerSearch(ISession session, CustomerSearch e) { return new Expression().List<Models.Customers, Customer>(); } public IList<Order> OnOrderSearch(ISession session, OrderSearch e) { Expression exp = new Expression(); if (e.CustomerID != null) exp &= Models.Orders.customerID == e.CustomerID; if (e.EmployeeID > 0) exp &= Models.Orders.employeeID == e.EmployeeID; return exp.List<Models.Orders, Order>(); } public IList<OrderDetail> GetOrderDetail(ISession session, GetDetail e) { Expression exp = Models.OrderDetails.orderID == e.OrderID; JoinTable jt = Models.OrderDetails.productID.InnerJoin(Models.Products.productID); jt.Select("OrderDetails.*", Models.Products.productName.Name); return exp.List<OrderDetail>(jt); } }
- 客戶端
private ProtoSyncClient mClient = new ProtoSyncClient("127.0.0.1"); private void FrmMain_Load(object sender, EventArgs e) { cbEmployees.Items.Add(new Employee()); foreach (Employee item in mClient.Send<IList<Employee>>(new EmployeeSearch())) { cbEmployees.Items.Add(item); } cbCustomers.Items.Add(new Customer()); foreach (Customer item in mClient.Send<IList<Customer>>(new CustomerSearch())) { cbCustomers.Items.Add(item); } } private void cmdSearch_Click(object sender, EventArgs e) { OrderSearch os = new OrderSearch(); if (cbCustomers.SelectedItem != null) os.CustomerID = ((Customer)cbCustomers.SelectedItem).CustomerID; if (cbEmployees.SelectedItem != null) os.EmployeeID = ((Employee)cbEmployees.SelectedItem).EmployeeID; gdOrder.DataSource = mClient.Send<IList<Order>>(os); } private void gdOrder_SelectionChanged(object sender, EventArgs e) { if (gdOrder.SelectedRows.Count > 0) { Order order = (Order)gdOrder.SelectedRows[0].DataBoundItem; GetDetail getdetail = new GetDetail(); getdetail.OrderID = order.OrderID; gdDetail.DataSource = mClient.Send<IList<OrderDetail>>(getdetail); } }
AppModule
AppModule類似於asp.net的httpModule,它可以在EC服務中載實始化的時候進行載入,通過AppModule可以實現訊息處理,處理日誌,全域性資訊定義等相關主要功能。
public class FilterModel : IAppModel { public string Name { get { return "Filter"; } } private System.Threading.Timer mTimer; public void Init(IApplication application) { //application.Filters.Add(new LoginFilter()); application.Disconnected += (o, e) => { "{0} disposed applicaion event".Log4Info(e.Session.Channel.EndPoint); }; application.Connected += (o, e) => { "{0} connect applicaion event".Log4Info(e.ChannelConnectArgs.Channel.EndPoint); }; application.SendCompleted += (o, e) => { "{0} send completed applicaion event".Log4Info(e.Session.Channel.EndPoint); }; application.MethodProcess += (o, e) => { //application e.Application["Path"] = @"c:\"; //sexxion e.Session["folder"] = "aaa"; }; application.Error += (o, e) => { "{0} channel error {1}".Log4Error(e.Info.Channel.EndPoint, e.Info.Error.Message); }; mTimer = new System.Threading.Timer(o => { application.Server.Send(new User { Name = Guid.NewGuid().ToString("N"),CreateTime = DateTime.Now }, application.Server.GetOnlines()); }, null, 1000, 1000); } public string Command(string cmd) { throw new NotImplementedException(); } }
Filter
這個特性在EC上是提供比較有用的功能,通訊filter可以對呼叫方法加入許可權,日誌,攔載等邏輯功能。
public class AdminFilter : FilterAttribute { public override void Execute(IMethodContext context) { "admin filter ->{0}".Log4Debug(context.Handler); base.Execute(context); } } [Controller] public class Controller { [SkipFilter(typeof(LoginFilter))] [ThreadPool] public User Regisetr(ISession session, User user) { user.CreateTime = DateTime.Now; "Register invoke[Name:{0} Email:{1}]".Log4Debug(user.Name, user.EMail); return user; } [AdminFilter] public IList<User> Search(ISession session, Query query) { "Search invoke".Log4Debug(); List<User> users = new List<User>(); users.Add(new User()); users.Add(new User()); return users; } }
開源地址
https://github.com/IKende/ec/
https://github.com/IKende/ec/tree/master/Samples
開源原因
其實我個人不太多喜歡走開源路線,主要是工作和手頭上的一些產品太多,而這個產品可以說完善度已經達到90%,如果扔在那裡感覺有點可惜了,所以把產品開源出來,如果有興趣的朋友可以複製完善它。