十九、【.Net开源】EFW框架核心类库之WCF控制器
EFW框架源代码下载V1.1:http://pan.baidu.com/s/1qWJjo3U
EFW框架实例源代码下载:http://pan.baidu.com/s/1o6MAKCa
只有当你需要开发三层架构的系统并利用WCF作为系统的中间件,那么就需要使用WCF控制器。EFW框架中的Wcf控制器分为两个部分WcfClientController和WcfController,两者利用Wcf服务进行通讯,其中WcfClientController的功能与上章中的WinController控制器是一样的,而WcfController控制器就与WebController控制器类似实现客户端与后台逻辑的交互;WcfClientController是放在客户端中的与界面代码一个项目,而WcfController是放在后台WCF中间件中,这点我们一定要搞清楚,虽然安装包可以把所有程序集只打成一个,但是在程序运行的过程中客户端是不会执行后台的程序,而中间件也不会执行前台的程序,但是实体除外;实体在客户段只是作为一个数据结构使用,而在中间件除了可以当做数据结构,还能使用ORM中的相关操作;
本章主要内容通过解读框架源代码来学习WCF控制器是怎么实现的,以及学习控制器这种模式;还有就是框架中对于WCF服务使用仅仅只是为了实现客户端与服务端的通讯,并不会赞成把业务功能做成一个个服务提供给外部调用;然后把WCF通讯模块封装成了一个简单的WCF中间件程序;并且WCF中间件实现了路由器功能与负载均衡功能;
本文要点:
1.如何使用WCF控制器
2.WCF控制器的设计思路
3.控制器基类的BaseWCFClientController和BaseWCFController的实现
4.基于Json格式传递数据的JsonWCFController类的实现
5.自定义标签WCFControllerAttribute和WCFMethodAttribute的配置
6.客户端与服务端通讯WCF服务WCFHandlerService类的实现
WCF控制器源代码目录:
EFW框架控制器设计图:
1.如何使用WCF控制器
如上图,Book.Winform项目里包括界面文件frmBookManager.cs和WCF客户端控制器文件bookwcfclientController.cs,Books项目包括WCF控制器文件bookWcfController.cs,bookwcfclientController类继承框架中的BaseWCFClientController基类,bookWcfController类继承框架中的JsonWCFController基类。Books.Winform项目相当于WCF的客户端,Books项目就是WCF的服务端。
如上图,展示了bookwcfclientController客户端控制器与bookWcfController服务端控制器之间的调用关系;客户端执行保存书籍操作,通过InvokeWCFService方法访问服务端控制器,参数指定服务端控制器的名称bookWcfController和控制器的方法名称SaveBook,程序进入到服务端的bookWcfController对象并指定SaveBook方法中的逻辑代码保存数据到数据库;同样执行客户端获取书籍目录GetBook也是一样的过程,服务端GetBook返回的DataTable数据结构要转换为Json格式字符串传递到客户端,客户端接收Json数据再转换为DataTable绑定到界面上显示。
2.WCF控制器的设计思路
当初利用WCF技术设计三层架构的系统时,没想到是在控制器这层着手,想过在数据访问层做文章,把数据库操作对象oleDb封装成wcf服务,但是这样的话逻辑层代码等于要界面层代码一起,没有达到三层架构的目的,至少得逻辑层是在中间件上运行的;那么只得把把逻辑层封装成wcf服务,那必须把所有业务逻辑都进行一层包裹,开发的工作量不少,而且wcf服务多了部署起来又麻烦;后来想着WCF服务不能太多,一个就够了,而且逻辑层代码和界面层代码最好不需要更改,想着想着发现在控制器这层比较合适;把以前Winform版的控制器拆成两个部分客户端控制器和服务端控制器,客户端控制器的功能拥有Winform版控制器一样操作界面的职责,但不能调用逻辑层的代码的通过wcf服务访问服务端控制器,WCFHosting服务主机支撑着wcf服务端控制器的运行,对比web版系统WCFHosting服务主机相当于IIS,而wcf控制器相当于WebController控制器;所以这样一分析WCF系统就像Web版和Winform版的结合体,这样就让三种开发模式的各层代码达到最大化的重用,对比Winform版只需要改造一下控制器代码就由原来的二层架构变成了有中间件的三层模式;
Wcf客户端控制器必须继承框架中的BaseWCFClientController基类,wcf服务端控制器要继承JsonWCFController基类,而JsonWCFController又继承BaseWCFController基类;还有wcf服务器控制器类上需要指定自定义标签WCFControllerAttribute和WCFMethodAttribute;JsonWCFController类实现wcf服务利用Json格式进行数据传递,如果你觉得Json不适合可以自己扩展XMLWCFController或其他;WCFControllerAttribute和WCFMethodAttribute自定义标签标出系统中那些wcf控制器对象,这样客户端才能很方便的只要根据控制器名和方法名就可以访问控制器;
3.控制器基类的BaseWCFClientController和BaseWCFController的实现
框架中的源代码BaseWCFClientController基类的实现
BaseWCFClientController文件
/// <summary>
/// WCF控制器客户端基类
/// </summary>
public class BaseWCFClientController
{
private static readonly string myNamespace = "http://www.3yxx.com/";
/// <summary>
/// 客户端标识
/// </summary>
public string ClientID
{
get
{
return EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("WCFClientID").ToString();
}
}
/// <summary>
/// wcf服务对象
/// </summary>
public IapiWCFHandlerService WCFService
{
get
{
IapiWCFHandlerService _wcfService= EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("WCFService") as IapiWCFHandlerService;
if (WCFHeartbeat(_wcfService)==false)//|| ((System.ServiceModel.ClientBase<IapiWCFHandlerService>)(_wcfService)).State == CommunicationState.Faulted || ((System.ServiceModel.ClientBase<IapiWCFHandlerService>)(_wcfService)).State == CommunicationState.Closed)
{
//CreateWCFService(AppGlobal.cache.GetData("ClientService") as IClientService);
ReConnectionWCFService(AppGlobal.cache.GetData("ClientService") as IClientService);
_wcfService = EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("WCFService") as IapiWCFHandlerService;
}
return _wcfService;
}
} /// <summary>
/// 创建wcf服务
/// </summary>
/// <param name="mainfrm"></param>
public static void CreateWCFService(IClientService mainfrm)
{
try
{
NetTcpBinding binding = new NetTcpBinding("NetTcpBinding_WCFHandlerService");
//binding.OpenTimeout = TimeSpan.FromSeconds(10);
//binding.TransferMode = TransferMode.Buffered;
DuplexChannelFactory<IapiWCFHandlerService> mChannelFactory = new DuplexChannelFactory<IapiWCFHandlerService>(mainfrm, binding, System.Configuration.ConfigurationSettings.AppSettings["WCF_endpoint"]);
IapiWCFHandlerService wcfHandlerService = mChannelFactory.CreateChannel(); string routerID;
string mProxyID;
using (var scope = new OperationContextScope(wcfHandlerService as IContextChannel))
{
// 注意namespace必须和ServiceContract中定义的namespace保持一致,默认是:http://tempuri.org
//var myNamespace = "http://www.3yxx.com/";
// 注意Header的名字中不能出现空格,因为要作为Xml节点名。
routerID = Guid.NewGuid().ToString();
var router = System.ServiceModel.Channels.MessageHeader.CreateHeader("routerID", myNamespace, routerID);
OperationContext.Current.OutgoingMessageHeaders.Add(router);
mProxyID = wcfHandlerService.CreateDomain(GetLocalIPAddress());
} if (AppGlobal.cache.Contains("WCFClientID")) AppGlobal.cache.Remove("WCFClientID");
if (AppGlobal.cache.Contains("WCFService")) AppGlobal.cache.Remove("WCFService");
if (AppGlobal.cache.Contains("ClientService")) AppGlobal.cache.Remove("ClientService");
if (AppGlobal.cache.Contains("routerID")) AppGlobal.cache.Remove("routerID"); AppGlobal.cache.Add("WCFClientID", mProxyID);
AppGlobal.cache.Add("WCFService", wcfHandlerService);
AppGlobal.cache.Add("ClientService", mainfrm);
AppGlobal.cache.Add("routerID", routerID); //开启发送心跳
if (timer == null)
StartSendWCFHeartbeat();
else
timer.Start();
}
catch (Exception err)
{
throw new Exception(err.Message);
}
}
/// <summary>
/// 重新连接wcf服务
/// </summary>
/// <param name="mainfrm"></param>
public static void ReConnectionWCFService(IClientService mainfrm)
{
try
{
NetTcpBinding binding = new NetTcpBinding("NetTcpBinding_WCFHandlerService");
//binding.OpenTimeout = TimeSpan.FromSeconds(10);
//binding.TransferMode = TransferMode.Buffered;
DuplexChannelFactory<IapiWCFHandlerService> mChannelFactory = new DuplexChannelFactory<IapiWCFHandlerService>(mainfrm, binding, System.Configuration.ConfigurationSettings.AppSettings["WCF_endpoint"]);
IapiWCFHandlerService wcfHandlerService = mChannelFactory.CreateChannel(); using (var scope = new OperationContextScope(wcfHandlerService as IContextChannel))
{
var router = System.ServiceModel.Channels.MessageHeader.CreateHeader("routerID", myNamespace, AppGlobal.cache.GetData("routerID").ToString());
OperationContext.Current.OutgoingMessageHeaders.Add(router);
wcfHandlerService.ReConnection(AppGlobal.cache.GetData("WCFClientID").ToString());
} if (AppGlobal.cache.Contains("WCFService")) AppGlobal.cache.Remove("WCFService");
AppGlobal.cache.Add("WCFService", wcfHandlerService); //开启发送心跳
if (timer == null)
StartSendWCFHeartbeat();
else
timer.Start();
}
catch (Exception err)
{
return;
}
} //向服务端发送心跳,间隔时间为5s
static System.Timers.Timer timer;
static void StartSendWCFHeartbeat()
{
timer = new System.Timers.Timer();
timer.Interval = ;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
static Object syncObj = new Object();////定义一个静态对象用于线程部份代码块的锁定,用于lock操作
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock (syncObj)
{
try
{
IapiWCFHandlerService _wcfService = EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("WCFService") as IapiWCFHandlerService;
if (WCFHeartbeat(_wcfService) == false)
{
//CreateWCFService(AppGlobal.cache.GetData("ClientService") as IClientService);
ReConnectionWCFService(AppGlobal.cache.GetData("ClientService") as IClientService);
}
}
catch (Exception err)
{ throw new Exception(err.Message);
}
}
}
static bool WCFHeartbeat(IapiWCFHandlerService _wcfService)
{
try
{
using (var scope = new OperationContextScope(_wcfService as IContextChannel))
{
var router = System.ServiceModel.Channels.MessageHeader.CreateHeader("routerID", myNamespace, AppGlobal.cache.GetData("routerID").ToString());
OperationContext.Current.OutgoingMessageHeaders.Add(router);
return _wcfService.Heartbeat(AppGlobal.cache.GetData("WCFClientID").ToString());
}
}
catch (Exception err)
{
timer.Stop();
return false;
}
}
static string GetLocalIPAddress()
{
IPHostEntry IpEntry = Dns.GetHostEntry(Dns.GetHostName());
string myip = "";
foreach (IPAddress ip in IpEntry.AddressList)
{
if (Regex.IsMatch(ip.ToString(), @"\d{0,3}\.\d{0,3}\.\d{0,3}\.\d{0,3}"))
{
myip = ip.ToString();
break;
}
}
return myip;
} /// <summary>
/// 获取登录用户信息
/// </summary>
public SysLoginRight GetSysLoginRight
{
get
{
if (EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("RoleUser") != null)
{
return (SysLoginRight)EFWCoreLib.CoreFrame.Init.AppGlobal.cache.GetData("RoleUser");
}
else
{
return new SysLoginRight();
}
}
} internal IBaseView _defaultView;
public IBaseView DefaultView
{
get { return _defaultView; }
} private Dictionary<string, IBaseView> _iBaseView;
public Dictionary<string, IBaseView> iBaseView
{
get { return _iBaseView; }
set
{
_iBaseView = value;
foreach (KeyValuePair<string, IBaseView> val in _iBaseView)
{
//val.Value.ControllerEvent += new ControllerEventHandler(UI_ControllerEvent);
val.Value.InvokeController = new ControllerEventHandler(UI_ControllerEvent);
}
}
} public CloseTab closeTab; /// <summary>
/// 创建BaseWCFClientController的实例
/// </summary>
public BaseWCFClientController()
{ }
/// <summary>
/// 界面控制事件
/// </summary>
/// <param name="eventname">事件名称</param>
/// <param name="objs">参数数组</param>
/// <returns></returns>
public virtual object UI_ControllerEvent(string eventname, params object[] objs)
{ MethodInfo meth= this.GetType().GetMethod(eventname);
if (meth != null)
{ return meth.Invoke(this, objs);
} switch (eventname)
{
case "Close":
if (closeTab != null)
closeTab();
break;
case "this":
return this;
default:
break;
} return null;
} /// <summary>
/// 初始化全局web服务参数对象
/// </summary>
public virtual void Init() { } public virtual IBaseView GetView(string frmName)
{
return iBaseView[frmName];
} public virtual Object InvokeWCFService(string controller, string method, string jsondata)
{ string retJson;
using (var scope = new OperationContextScope(WCFService as IContextChannel))
{
var router = System.ServiceModel.Channels.MessageHeader.CreateHeader("routerID", myNamespace, AppGlobal.cache.GetData("routerID").ToString());
OperationContext.Current.OutgoingMessageHeaders.Add(router);
retJson = WCFService.ProcessRequest(ClientID, controller, method, jsondata);
}
object Result = JavaScriptConvert.DeserializeObject(retJson);
int ret = Convert.ToInt32(((Newtonsoft.Json.JavaScriptObject)(Result))["flag"]);
string msg = ((Newtonsoft.Json.JavaScriptObject)(Result))["msg"].ToString();
if (ret == )
{
throw new Exception(msg);
}
else
{
return ((Newtonsoft.Json.JavaScriptObject)(Result))["data"];
}
} public virtual Object InvokeWCFService(string controller, string method, params object[] data)
{
//
string jsondata = JavaScriptConvert.SerializeObject(data, new AspNetDateTimeConverter());
return InvokeWCFService(controller, method, jsondata);
} private object convertVal(Type t, object data)
{
object val = null;
if (t == typeof(Int32))
val = Convert.ToInt32(data);
else if (t == typeof(DateTime))
val = Convert.ToDateTime(data);
else if (t == typeof(Decimal))
val = Convert.ToDecimal(data);
else if (t == typeof(Boolean))
val = Convert.ToBoolean(data);
else if (t == typeof(String))
val = Convert.ToString(data).Trim();
else if (t == typeof(Guid))
val = new Guid(data.ToString());
else
val = data;
return val;
} public object[] ToArray(object data)
{
return (data as Newtonsoft.Json.JavaScriptArray).ToArray();
}
public List<T> ToListObj<T>(object data)
{
if (data is JavaScriptArray)
{
PropertyInfo[] pros = typeof(T).GetProperties();
List<T> list = new List<T>();
for (int i = ; i < (data as JavaScriptArray).Count; i++)
{
T obj = (T)Activator.CreateInstance(typeof(T));
object _data = (data as JavaScriptArray)[i];
for (int k = ; k < pros.Length; k++)
{
object val = convertVal(pros[k].PropertyType, (_data as JavaScriptObject)[pros[k].Name]);
pros[k].SetValue(obj, val, null);
}
list.Add(obj);
}
return list;
} return null;
}
public DataTable ToDataTable(object data)
{
if (data is JavaScriptArray && (data as JavaScriptArray).Count>)
{
JavaScriptObject _data = (data as JavaScriptArray)[] as JavaScriptObject;
DataTable dt=new DataTable();
foreach (var name in _data.Keys)
{
dt.Columns.Add(name, _data[name].GetType());
} for (int i = ; i < (data as JavaScriptArray).Count; i++)
{
object _jsarray = (data as JavaScriptArray)[i];
DataRow dr= dt.NewRow();
for (int k = ; k < dt.Columns.Count; k++)
{
dr[k] = convertVal(dt.Columns[k].DataType, (_jsarray as JavaScriptObject)[dt.Columns[k].ColumnName]);
}
dt.Rows.Add(dr);
} return dt;
}
return null;
}
public T ToObject<T>(object data)
{
T obj = (T)Activator.CreateInstance(typeof(T));
PropertyInfo[] pros = typeof(T).GetProperties();
for (int k = ; k < pros.Length; k++)
{
object val = convertVal(pros[k].PropertyType, (data as JavaScriptObject)[pros[k].Name]);
pros[k].SetValue(obj, val, null);
} return obj;
} }
框架中的源代码BaseWCFController基类的实现
BaseWCFController文件
/// <summary>
/// WCF控制器服务端基类
/// </summary>
public class BaseWCFController : AbstractBusines
{
/// <summary>
/// 数据库操作对象
/// </summary>
public AbstractDatabase oleDb
{
get
{
return _oleDb;
}
}
/// <summary>
/// 当前客户端信息
/// </summary>
public WCFClientInfo ClientInfo
{
get;
set;
}
/// <summary>
/// 当前登录用户信息
/// </summary>
public SysLoginRight GetSysLoginRight
{
get
{
if (ClientInfo != null && ClientInfo.LoginRight != null)
return ClientInfo.LoginRight;
return new SysLoginRight();
}
} //public ViewEventHandler ViewHandler
//{
// get { return RemoteLoaderController.ViewHandler; }
//} /// <summary>
/// 客户端传递的参数
/// </summary>
public string ParamJsonData
{
get;
set;
} /// <summary>
/// 创建BaseWCFController的实例
/// </summary>
public BaseWCFController()
{ } /// <summary>
/// 初始化全局web服务参数对象
/// </summary>
public virtual void Init() { }
}
BaseWCFClientController基类封装的功能包括:
1)WCF服务对象,利用InvokeWCFService方法就可以调用服务端控制器
2)系统登录后的用户信息GetSysLoginRight,这样客户端控制器中就可以很方便的获取登录用户信息;
3)与Winform版控制器类似的对界面操作的iBaseView
4)将Json字符串转换为对象的方法
BaseWCFController基类封装的功能包括:
1)数据库操作对象oleDb
2)系统的当前登录用户信息GetSysLoginRight
4.基于Json格式传递数据的JsonWCFController类的实现
框架中的源代码JsonWCFController基类,实现数据结构转换为Json格式的字符串;用Json格式主要是觉得它是一种轻量级的数据交换格式,还有就是和web版的保持一致;
JsonWCFController文件
/// <summary>
/// 基于Json格式的WCF服务基类
/// </summary>
public class JsonWCFController : BaseWCFController, IToJson, EFWCoreLib.WCFHandler.IJsonToObject
{
#region 值转换
private object convertVal(Type t, object data)
{
object val = null;
if (t == typeof(Int32))
val = Convert.ToInt32(data);
else if (t == typeof(DateTime))
val = Convert.ToDateTime(data);
else if (t == typeof(Decimal))
val = Convert.ToDecimal(data);
else if (t == typeof(Boolean))
val = Convert.ToBoolean(data);
else if (t == typeof(String))
val = Convert.ToString(data).Trim();
else if (t == typeof(Guid))
val = new Guid(data.ToString());
else
val = data;
return val;
}
#endregion #region IToJson 成员 public string ToJson(object model)
{
string value = JavaScriptConvert.SerializeObject(model, new AspNetDateTimeConverter());
return value;
} public string ToJson(System.Data.DataTable dt)
{
string value = JavaScriptConvert.SerializeObject(dt);
return value;
} public string ToJson(params object[] data)
{
string value = JavaScriptConvert.SerializeObject(data, new AspNetDateTimeConverter());
return value;
} #endregion #region IJsonToObject成员
public T ToObject<T>(string json)
{
return JavaScriptConvert.DeserializeObject<T>(json);
} public object ToObject(string json)
{
return JavaScriptConvert.DeserializeObject(json);
} public object[] ToArray(object data)
{
return (data as Newtonsoft.Json.JavaScriptArray).ToArray();
} public List<T> ToListObj<T>(object data)
{
if (data is JavaScriptArray)
{
PropertyInfo[] pros = typeof(T).GetProperties();
List<T> list = new List<T>();
for (int i = ; i < (data as JavaScriptArray).Count; i++)
{
T obj = (T)Activator.CreateInstance(typeof(T));
object _data = (data as JavaScriptArray)[i];
for (int k = ; k < pros.Length; k++)
{
object val = convertVal(pros[k].PropertyType, (_data as JavaScriptObject)[pros[k].Name]);
pros[k].SetValue(obj, val, null);
}
list.Add(obj);
}
return list;
} return null;
} public DataTable ToDataTable(object data)
{
if (data is JavaScriptArray && (data as JavaScriptArray).Count > )
{
JavaScriptObject _data = (data as JavaScriptArray)[] as JavaScriptObject;
DataTable dt = new DataTable();
foreach (var name in _data.Keys)
{
dt.Columns.Add(name, _data[name].GetType());
} for (int i = ; i < (data as JavaScriptArray).Count; i++)
{
object _jsarray = (data as JavaScriptArray)[i];
DataRow dr = dt.NewRow();
for (int k = ; k < dt.Columns.Count; k++)
{
dr[k] = convertVal(dt.Columns[k].DataType, (_jsarray as JavaScriptObject)[dt.Columns[k].ColumnName]);
}
dt.Rows.Add(dr);
} return dt;
}
return null;
} public T ToObject<T>(object data)
{
T obj = (T)Activator.CreateInstance(typeof(T));
PropertyInfo[] pros = typeof(T).GetProperties();
for (int k = ; k < pros.Length; k++)
{
object val = convertVal(pros[k].PropertyType, (data as JavaScriptObject)[pros[k].Name]);
pros[k].SetValue(obj, val, null);
} return obj;
}
#endregion
}
5.自定义标签WCFControllerAttribute和WCFMethodAttribute的配置
配置WCFControllerAttribute和WCFMethodAttribute标签的目的就是减少暴露给客户端的对象,只有指定了标签的对象才能被客户端所调用;而且让客户端调用的方式更简单,只需指定控制器的名称和方法名就行了;所以后台代码不能有相同名称的控制器对象,如果指定相同的控制器名称那么识别不了;
WCFControllerAttribute文件
/// <summary>
/// WCF服务对象自定义标签
/// </summary>
[AttributeUsageAttribute(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class WCFControllerAttribute : Attribute
{
string _memo;
public string Memo
{
get { return _memo; }
set { _memo = value; }
}
}
WCFMethodAttribute文件
[AttributeUsageAttribute(AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
public class WCFMethodAttribute : Attribute
{
private string _openDBNames;
/// <summary>
/// 打开数据库,中间用,号隔开
/// </summary>
public string OpenDBKeys
{
get { return _openDBNames; }
set { _openDBNames = value; }
}
private string _memo;
public string Memo
{
get { return _memo; }
set { _memo = value; }
}
}
6.客户端与服务端通讯WCF服务WCFHandlerService类的实现
客户端与服务端是利用wcf服务进行通信的,而WCFHandlerService类就是实现的WCF服务对象,WCFHandlerService对象实现调用wcf服务端控制器的操作契约就是ProcessRequest方法,本章先讲解一下此核心方法,其他的功能在后面讲WcfHosting服务主机的时候会详细讲解;
WCFHandlerService文件
public string ProcessRequest(string mProxyID, string controller, string method, string jsondata)
{
try
{
if (Convert.ToInt32(HostSettingConfig.GetValue("debug")) == )
Loader.ShowHostMsg(DateTime.Now, "客户端[" + mProxyID + "]正在执行:" + controller + "." + method + "(" + jsondata + ")");
string retJson = Loader.ProcessRequest(mProxyID, controller, method, jsondata);
return "{\"flag\":0,\"msg\":" + "\"\"" + ",\"data\":" + retJson + "}";
}
catch (Exception err)
{
if (err.InnerException == null)
{
Loader.ShowHostMsg(DateTime.Now, "客户端[" + mProxyID + "]执行失败:" + controller + "." + method + "(" + jsondata + ")\n错误原因:" + err.Message);
return "{\"flag\":1,\"msg\":" + "\"" + err.Message + "\"" + "}";
}
else
{
Loader.ShowHostMsg(DateTime.Now, "客户端[" + mProxyID + "]执行失败:" + controller + "." + method + "(" + jsondata + ")\n错误原因:" + err.InnerException.Message);
return "{\"flag\":1,\"msg\":" + "\"" + err.InnerException.Message + "\"" + "}";
}
}
}
十九、【.Net开源】EFW框架核心类库之WCF控制器的更多相关文章
- 十七、EnterpriseFrameWork框架核心类库之Web控制器
回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U EFW框架中的WebContro ...
- 二十、【.Net开源】EFW框架核心类库之WebService服务
回<[开源]EFW框架系列文章索引> EFW框架源代码下载V1.1:http://pan.baidu.com/s/1qWJjo3U EFW框架实例源代码下载:http://pan.baid ...
- 十八、【开源】EnterpriseFrameWork框架核心类库之Winform控制器
回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U EFW框架中的WinContro ...
- 第三百一十九节,Django框架,文件上传
第三百一十九节,Django框架,文件上传 1.自定义上传[推荐] 请求对象.FILES.get()获取上传文件的对象上传对象.name获取上传文件名称上传对象.chunks()获取上传数据包,字节码 ...
- WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载]
原文:WCF技术剖析之二十九:换种不同的方式调用WCF服务[提供源代码下载] 我们有两种典型的WCF调用方式:通过SvcUtil.exe(或者添加Web引用)导入发布的服务元数据生成服务代理相关的代码 ...
- 十六、【适合中小企业的.Net轻量级开源框架】EnterpriseFrameWork框架核心类库之单点登录SSO
回<[开源]EnterpriseFrameWork框架系列文章索引> EFW框架源代码下载:http://pan.baidu.com/s/1qWJjo3U 单点登录(Single Sign ...
- 十二、EnterpriseFrameWork框架核心类库之与EntLib结合
从本章开始对框架的讲叙开始进入核心类库的讲解,前面都是对框架外在功能讲解,让人有个整体的概念,知道包含哪些功能与对系统开发有什么帮助.以后多章都是讲解核心类库的,讲解的方式基本按照代码的目录结构,这样 ...
- 十五、EnterpriseFrameWork框架核心类库之系统启动入口与初始化
本章内容是讲三种开发模式,web模式.Winform模式和Wcf模式的系统启动入口有什么区别,以及启动后系统初始化的内容:为什么要把这些单独提出来讲一章,因为我觉得本章非常重要,我们都知道程序中的ma ...
- 十四、EnterpriseFrameWork框架核心类库之简易ORM
在写本章前先去网上找了一下关于ORM的相关资料,以为本章做准备,发现很多东西今天才了解,所以在这里也对ORM做不了太深入的分析,但还是浅谈一下EFW框架中的设计的简易ORM:文中有一点讲得很有道理,D ...
随机推荐
- 移动开发下Xamarin VS PhoneGap
跨平台开发 移动应用开发对很多开发人员来说是一种令人恐惧的事情.许多企业希望能够通过开发移动应用程序,来提升企业业务水平,开发原生App时往往又缺少专业的Objective C 或 Java 移动开发 ...
- Firefox SVG getBBox方法返回'NS_ERROR_FAILURE'错误分析
在SVG中,我们无法给Text元素设置Width和Height属性,因此无法直接获取Text元素的高和宽.如果想要给Text元素添加背景色,最简单的办法就是在Text元素的下面添加Rect,然后给Re ...
- SSL双向认证java实现(转)
本文通过模拟场景,介绍SSL双向认证的java实现 默认的情况下,我认为读者已经对SSL原理有一定的了解,所以文章中对SSL的原理,不做详细的介绍. 如果有这个需要,那么通过GOOGLE,可以搜索到很 ...
- 无线电源传输 Wireless Power Consortium (WPC) Communication
Universally Compatible Wireless Power Using the Qi Protocol Wireless charging of portable electronic ...
- 分享一些无特征PHP一句话
分享些不需要动态函数.不用eval.不含敏感函数.免杀免拦截的一句话.(少部分一句话需要php5.4.8+.或sqlite/pdo/yaml/memcached扩展等) 原理:https://www. ...
- Win7任务栏图标大小调整为等宽
打开注册表,找到HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics,新建DWORD,输入MinWidth,大图标设为56,小图标设定为36: 参 ...
- chrome start.js报错
是由 chrome 插件 “电脑管家广告过滤” 引起的 并且,在用户电脑上还出现了这个插件拦截正常请求的情况 如果同时报以下错误: Uncaught TypeError: Cannot read pr ...
- android Studio NDK
官方文档地址: https://developer.android.com/studio/projects/add-native-code.html#download-ndk 最近推出CMake方式集 ...
- javascript 的一些理解和随笔
一.iframe里面的页面调用父窗口,左右窗口js函数的方法 iframe里面的页面调用父窗口,左右窗口js函数的方法 实现iframe内部页面直接调用该iframe所属父窗口自定义函数的方法. 比如 ...
- How to get the Current Controller Name, Action, or ID in ASP.NET MVC
public static class HtmlRequestHelper { public static string Id(this HtmlHelper htmlHelper) { var ro ...