Skip to content

Commit

Permalink
处理请求消息。重载、事件、控制器 共三种消息处理方式
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Jan 19, 2017
1 parent 24938b7 commit 0efe6ce
Show file tree
Hide file tree
Showing 9 changed files with 238 additions and 184 deletions.
1 change: 1 addition & 0 deletions NewLife.Core/NewLife.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@
<Compile Include="Remoting\ApiAction.cs" />
<Compile Include="Remoting\ApiAttribute.cs" />
<Compile Include="Remoting\ApiException.cs" />
<Compile Include="Remoting\ApiHost.cs" />
<Compile Include="Remoting\Controllers\ApiController.cs" />
<Compile Include="Remoting\Filters\ActionFilterAttribute.cs" />
<Compile Include="Remoting\Filters\ApiFilterContext.cs" />
Expand Down
38 changes: 24 additions & 14 deletions NewLife.Core/Remoting/ApiClient.cd
Original file line number Diff line number Diff line change
@@ -1,72 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="NewLife.Remoting.ApiClient" Collapsed="true">
<Position X="3.5" Y="5" Width="1.5" />
<Position X="3.5" Y="4" Width="1.5" />
<TypeIdentifier>
<HashCode>ACAAAAAAhCAMKAAACIAACAAAEAgBBAARAAAAAACBAEQ=</HashCode>
<HashCode>ACAAAAAAgCAEIAAAAAAACAAAEAgAAAAQAAAAAACBAEQ=</HashCode>
<FileName>Remoting\ApiClient.cs</FileName>
</TypeIdentifier>
<ShowAsAssociation>
<Property Name="Client" />
<Property Name="Encoder" />
<Property Name="Handler" />
<Property Name="Manager" />
</ShowAsAssociation>
<Lollipop Position="0.2" />
</Class>
<Class Name="NewLife.Remoting.ApiAction" Collapsed="true">
<Position X="3.5" Y="9" Width="1.5" />
<Position X="0.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAQAAAAAEIAAkQAQAAAAAAAgAAAAAAAAAAAA=</HashCode>
<FileName>Remoting\ApiAction.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="NewLife.Remoting.JsonEncoder" Collapsed="true">
<Position X="5.5" Y="1.75" Width="1.5" />
<Position X="3.5" Y="6.75" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAABAAAAAAIAAAAAAgAAAAAAAAAAAQAAAAAA=</HashCode>
<FileName>Remoting\JsonEncoder.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="NewLife.Remoting.EncoderBase" Collapsed="true">
<Position X="5.5" Y="0.5" Width="1.5" />
<Position X="3.5" Y="5.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAABAAAAAAMAAAAAAAAgAAAAAAAABQAAAAAA=</HashCode>
<FileName>Remoting\IEncoder.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="NewLife.Remoting.ApiHttpClient" Collapsed="true">
<Position X="2.5" Y="2" Width="1.5" />
<Position X="6.5" Y="4" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAA=</HashCode>
<FileName>Remoting\ApiHttpClient.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="NewLife.Remoting.ApiNetClient" Collapsed="true">
<Position X="2.5" Y="0.5" Width="1.5" />
<Position X="6.5" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AABAAAAAACAEIAAAAAAACAAAEAgAAACAAAACAADAAEQ=</HashCode>
<FileName>Remoting\ApiNetClient.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Class Name="NewLife.Remoting.ApiHost" Collapsed="true">
<Position X="3.5" Y="2.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAABBAAcCAAACoAAAAAEAAABBAABAAAAAAAAAEA=</HashCode>
<FileName>Remoting\ApiHost.cs</FileName>
</TypeIdentifier>
<ShowAsAssociation>
<Property Name="Encoder" />
<Property Name="Handler" />
<Property Name="Manager" />
</ShowAsAssociation>
<Lollipop Position="0.2" />
</Class>
<Interface Name="NewLife.Remoting.IApiClient" Collapsed="true">
<Position X="0.5" Y="7" Width="1.5" />
<Position X="0.5" Y="4" Width="1.5" />
<TypeIdentifier>
<HashCode>AABAAAAAAAAEIAAAAAAAAAAAEAgAAACAAAACAACAAAA=</HashCode>
<FileName>Remoting\IApiClient.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="NewLife.Remoting.IEncoder" Collapsed="true">
<Position X="6.5" Y="5" Width="1.5" />
<Position X="3.5" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAABAAAAAAIAAAAAAAAgAAAAAAAABQAAAAAA=</HashCode>
<FileName>Remoting\IEncoder.cs</FileName>
</TypeIdentifier>
</Interface>
<Interface Name="NewLife.Remoting.IApiHandler" Collapsed="true">
<Position X="0.5" Y="5" Width="1.5" />
<Position X="6.5" Y="0.5" Width="1.5" />
<Compartments>
<Compartment Name="Methods" Collapsed="true" />
</Compartments>
Expand All @@ -76,7 +86,7 @@
</TypeIdentifier>
</Interface>
<Interface Name="NewLife.Remoting.IApiManager" Collapsed="true">
<Position X="3.5" Y="7" Width="1.5" />
<Position X="0.5" Y="2.5" Width="1.5" />
<Compartments>
<Compartment Name="Methods" Collapsed="true" />
</Compartments>
Expand Down
54 changes: 4 additions & 50 deletions NewLife.Core/Remoting/ApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace NewLife.Remoting
{
/// <summary>应用接口客户端</summary>
[Api(null)]
public class ApiClient : DisposeBase, IApiHost, IApiSession, IServiceProvider
public class ApiClient : ApiHost, IApiSession
{
#region 静态
/// <summary>协议到提供者类的映射</summary>
Expand All @@ -32,28 +32,8 @@ static ApiClient()
/// <summary>通信客户端</summary>
public IApiClient Client { get; set; }

/// <summary>编码器。用于对象与字节数组相互转换</summary>
public IEncoder Encoder { get; set; }

/// <summary>处理器</summary>
public IApiHandler Handler { get; set; }

/// <summary>过滤器</summary>
public IList<IFilter> Filters { get; } = new List<IFilter>();

/// <summary>所有服务器所有会话,包含自己</summary>
IApiSession[] IApiSession.AllSessions { get { return new IApiSession[] { this }; } }

/// <summary>用户会话数据</summary>
public IDictionary<String, Object> Items { get; set; } = new NullableDictionary<String, Object>();

/// <summary>获取/设置 用户会话数据</summary>
/// <param name="key"></param>
/// <returns></returns>
public virtual Object this[String key] { get { return Items[key]; } set { Items[key] = value; } }

/// <summary>是否在会话上复用控制器。复用控制器可确保同一个会话多次请求路由到同一个控制器对象实例</summary>
public Boolean IsReusable { get; set; } = true;
#endregion

#region 构造
Expand Down Expand Up @@ -160,42 +140,16 @@ public async Task<TResult> InvokeAsync<TResult>(String action, object args = nul
async Task<IMessage> IApiSession.SendAsync(IMessage msg) { return await Client.SendAsync(msg); }
#endregion

#region 控制器管理
/// <summary>接口动作管理器</summary>
public IApiManager Manager { get; } = new ApiManager();

/// <summary>注册服务提供类。该类的所有公开方法将直接暴露</summary>
/// <typeparam name="TService"></typeparam>
public void Register<TService>() where TService : class, new()
{
Manager.Register<TService>();
}

/// <summary>注册服务</summary>
/// <param name="controller">控制器对象或类型</param>
/// <param name="method">动作名称。为空时遍历控制器所有公有成员方法</param>
public void Register(Object controller, String method)
{
Manager.Register(controller, method);
}
#endregion

#region 服务提供者
/// <summary>服务提供者</summary>
public IServiceProvider Provider { get; set; }

/// <summary>获取服务提供者</summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public Object GetService(Type serviceType)
public override Object GetService(Type serviceType)
{
if (serviceType == GetType()) return this;
if (serviceType == typeof(IApiHost)) return this;
if (serviceType == typeof(IApiManager)) return Manager;
if (serviceType == typeof(IEncoder) && Encoder != null) return Encoder;
if (serviceType == typeof(IApiHandler) && Handler != null) return Handler;
if (serviceType == typeof(IApiClient)) return this;

return Provider?.GetService(serviceType);
return base.GetService(serviceType);
}
#endregion

Expand Down
156 changes: 156 additions & 0 deletions NewLife.Core/Remoting/ApiHost.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using NewLife.Collections;
using NewLife.Data;
using NewLife.Messaging;

namespace NewLife.Remoting
{
/// <summary>Api主机</summary>
public abstract class ApiHost : DisposeBase, IApiHost, IServiceProvider
{
#region 属性
/// <summary>编码器</summary>
public IEncoder Encoder { get; set; }

/// <summary>处理器</summary>
public IApiHandler Handler { get; set; }

/// <summary>过滤器</summary>
public IList<IFilter> Filters { get; } = new List<IFilter>();

/// <summary>用户会话数据</summary>
public IDictionary<String, Object> Items { get; set; } = new NullableDictionary<String, Object>();

/// <summary>获取/设置 用户会话数据</summary>
/// <param name="key"></param>
/// <returns></returns>
public virtual Object this[String key] { get { return Items[key]; } set { Items[key] = value; } }

/// <summary>是否在会话上复用控制器。复用控制器可确保同一个会话多次请求路由到同一个控制器对象实例</summary>
public Boolean IsReusable { get; set; }
#endregion

#region 控制器管理
/// <summary>接口动作管理器</summary>
public IApiManager Manager { get; } = new ApiManager();

/// <summary>注册服务提供类。该类的所有公开方法将直接暴露</summary>
/// <typeparam name="TService"></typeparam>
public void Register<TService>() where TService : class, new()
{
Manager.Register<TService>();
}

/// <summary>注册服务</summary>
/// <param name="controller">控制器对象或类型</param>
/// <param name="method">动作名称。为空时遍历控制器所有公有成员方法</param>
public void Register(Object controller, String method)
{
Manager.Register(controller, method);
}
#endregion

#region 请求处理
/// <summary>收到请求</summary>
public event EventHandler<ApiMessageEventArgs> Received;

/// <summary>处理消息</summary>
/// <param name="session"></param>
/// <param name="msg"></param>
/// <returns></returns>
IMessage IApiHost.Process(IApiSession session, IMessage msg)
{
if (msg.Reply) return null;

// 过滤器
this.ExecuteFilter(msg, false);

var rs = OnReceive(session, msg);

// 过滤器
this.ExecuteFilter(rs, true);

return rs;
}

/// <summary>处理请求消息。重载、事件、控制器 共三种消息处理方式</summary>
/// <param name="session"></param>
/// <param name="msg"></param>
/// <returns></returns>
protected virtual IMessage OnReceive(IApiSession session, IMessage msg)
{
// 优先调用外部事件
if (Received != null)
{
var e = new ApiMessageEventArgs
{
Session = session,
Message = msg
};
Received(this, e);

if (e.Handled) return e.Message;
}

var pk = msg.Payload;
// 如果外部事件未处理,再交给处理器
pk = ProcessHandler(session, pk);

// 封装响应消息
var rs = msg.CreateReply();
rs.Payload = pk;

return rs;
}

private Packet ProcessHandler(IApiSession session, Packet pk)
{
var enc = Encoder;

// 这里会导致二次解码,因为解码以后才知道是不是请求
var dic = enc.Decode(pk);

var action = "";
Object args = null;
if (!enc.TryGet(dic, out action, out args)) return null;

object result = null;
var code = 0;
try
{
result = Handler.Execute(session, action, args as IDictionary<String, Object>).Result;
}
catch (Exception ex)
{
var aex = ex as ApiException;
code = aex != null ? aex.Code : 500;
result = ex;
}

// 编码响应数据包
return enc.Encode(code, result);
}
#endregion

#region 服务提供者
/// <summary>服务提供者</summary>
public IServiceProvider Provider { get; set; }

/// <summary>获取服务提供者</summary>
/// <param name="serviceType"></param>
/// <returns></returns>
public virtual Object GetService(Type serviceType)
{
if (serviceType == GetType()) return this;
if (serviceType == typeof(ApiHost)) return this;
if (serviceType == typeof(IApiHost)) return this;
if (serviceType == typeof(IApiManager)) return Manager;
if (serviceType == typeof(IEncoder) && Encoder != null) return Encoder;
if (serviceType == typeof(IApiHandler) && Handler != null) return Handler;

return Provider?.GetService(serviceType);
}
#endregion
}
}
2 changes: 1 addition & 1 deletion NewLife.Core/Remoting/ApiNetClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private void Client_Received(Object sender, MessageEventArgs e)
var msg = e.Message;
if (msg.Reply) return;

var host = this.GetService<ApiClient>();
var host = this.GetService<IApiHost>();

var rs = host.Process(this.GetService<IApiSession>(), msg);
if (rs != null) Client.SendAsync(rs);
Expand Down
Loading

0 comments on commit 0efe6ce

Please sign in to comment.