nonepassby

导航

CSLA.NET快速入门系列——实现DataPortal扩展(二)

在 CSLA.NET快速入门系列——实现DataPortal扩展(一) 中我们介绍了实现DataPortal扩展的步骤和DataPortal扩展实际的流程,并提出一个实际DataPortal扩展需求。

在要本篇中我们介绍第一步骤:实现Csla.DataPortalClient.IDataPortalProxy

 

IDataPortalProxy接口包含1个属性和四个方法:

 

// 摘要:
        
//     Get a value indicating whether this proxy will invoke a remote data portal
        
//     server, or run the "server-side" data portal in the caller's process and
        
//     AppDomain.
bool IsServerRemote { get; }
// 摘要:
        
//     Create a new business object.
        
//
        
// 参数:
        
//   objectType:
        
//     Type of business object to create.
        
//
        
//   criteria:
        
//     Criteria object describing business object.
        
//
        
//   context:
        
//     Csla.Server.DataPortalContext object passed to the server.
        DataPortalResult Create(Type objectType, object criteria, DataPortalContext context);
        //
        
// 摘要:
        
//     Delete a business object.
        
//
        
// 参数:
        
//   objectType:
        
//     Type of business object to create.
        
//
        
//   criteria:
        
//     Criteria object describing business object.
        
//
        
//   context:
        
//     Csla.Server.DataPortalContext object passed to the server.
        DataPortalResult Delete(Type objectType, object criteria, DataPortalContext context);
        //
        
// 摘要:
        
//     Get an existing business object.
        
//
        
// 参数:
        
//   objectType:
        
//     Type of business object to retrieve.
        
//
        
//   criteria:
        
//     Criteria object describing business object.
        
//
        
//   context:
        
//     Csla.Server.DataPortalContext object passed to the server.
        DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context);
        //
        
// 摘要:
        
//     Update a business object.
        
//
        
// 参数:
        
//   obj:
        
//     Business object to update.
        
//
        
//   context:
        
//     Csla.Server.DataPortalContext object passed to the server.
        DataPortalResult Update(object obj, DataPortalContext context);

 

其中四个方法返回的都是Csla.Server.DataPortalResult类型,在Csla的DataPortal框架中可以接收这种类型的结果并更新业务对象的状态。

 

由于 1、采用远程DataPortal,以Wcf作为客户端和服务端连接的方式,需要定义一个wcf的服务契约:

定义四个方法分别用来传送IDataPortalProxy接口相应的方法,

又由于 2、业务对象在移动过程中采用二进制序列化的方式,因此,此契约的参数和返回值必须包含二进制序列化数据。

代码如下:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Csla.Server.Hosts.WcfChannel;

namespace ITLead.CslaExtend.Server.Hosts
{
    /// <summary>
    
/// WcfPortal扩展接口
    
/// </summary>
  [ServiceContract(Namespace = "http://www.itlead.com.cn/extendwcfportal")]
  public interface IExtendWcfPortal
  {
      /// <summary>
      
/// 创建业务对象
      
/// </summary>
      
/// <param name="request"></param>
      
/// <returns></returns>
    [OperationContract]
    [UseNetDataContract]
    WcfResponse Create(CriteriaRequest request);

      /// <summary>
      
/// 获取业务对象
      
/// </summary>
      
/// <param name="request"></param>
      
/// <returns></returns>
    [OperationContract]
    [UseNetDataContract]
    WcfResponse Fetch(CriteriaRequest request);

      /// <summary>
      
/// 更新业务对象
      
/// </summary>
      
/// <param name="request"></param>
      
/// <returns></returns>
    [OperationContract]
    [UseNetDataContract]
    WcfResponse Update(UpdateRequest request);

      /// <summary>
      
/// 删除业务对象
      
/// </summary>
      
/// <param name="request"></param>
      
/// <returns></returns>
    [OperationContract]
    [UseNetDataContract]
    WcfResponse Delete(CriteriaRequest request);
  }
}

契约中的参数我们在下篇再做说明。

 

现在,我们可以实现自己的DataPortalProxy类:

代码如下:

 

using System;
using System.ServiceModel;
using Csla.Server;
using Csla.Serialization;
using Csla.Core;
using Csla;
using ITLead.CslaExtend.Server.Hosts;

namespace ITLead.CslaExtend.DataPortalClient
{
    /// <summary>
    
/// 二进制序列化wcf服务代理
    
/// </summary>
    public class BFWcfProxy : Csla.DataPortalClient.IDataPortalProxy
    {
        #region IDataPortalProxy Members

        /// <summary>
        
/// 获取服务器是否在远程,始终返回真
        
/// </summary>
        public bool IsServerRemote
        {
            get { return true; }
        }

        #endregion

        #region IDataPortalServer Members

        private string _endPoint = "BFWcfDataPortal";

        /// <summary>
        
/// WCF EndPoint
        
/// </summary>
        
/// <remarks>
        
/// 默认为BFWcfDataPortal
        
/// </remarks>
        protected virtual string EndPoint
        {
            get
            {
                return _endPoint;
            }
            set
            {
                _endPoint = value;
            }
        }

        /// <summary>
        
/// 获取通道工厂
        
/// </summary>
        
/// <remarks>为了保持和Csla一致,也可以配置DataPortalUrl</remarks>
        protected virtual ChannelFactory<IExtendWcfPortal> GetChannelFactory()
        {
            if (!string.IsNullOrEmpty(ApplicationContext.DataPortalUrlString))
            {
                var binding = new WSHttpBinding()
                {
                    MaxReceivedMessageSize = int.MaxValue,
                    ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas()
                    {
                        MaxBytesPerRead = int.MaxValue,
                        MaxDepth = int.MaxValue,
                        MaxArrayLength = int.MaxValue,
                        MaxStringContentLength = int.MaxValue,
                        MaxNameTableCharCount = int.MaxValue
                    }
                };
                return new ChannelFactory<IExtendWcfPortal>(binding, new EndpointAddress(ApplicationContext.DataPortalUrl));
            }
            return new ChannelFactory<IExtendWcfPortal>(EndPoint);
        }

        /// <summary>
        
/// 获取WcfDataPortal的代理
        
/// </summary>
        
/// <param name="cf">
        
/// 通过GetChannelFactory()方法创建的通道工厂
        
/// </param>
        protected virtual IExtendWcfPortal GetProxy(ChannelFactory<IExtendWcfPortal> cf)
        {
            return cf.CreateChannel();
        }

        /// <summary>
        
/// 创建业务对象
        
/// </summary>
        
/// <param name="objectType">要创建的业务对象类型</param>
        
/// <param name="criteria">描述要创建的业务对象的Criteria对象</param>
        
/// <param name="context">
        
/// <see cref="Server.DataPortalContext" /> 要传递的DataPortal服务器的上下文.
        
/// </param>
        public DataPortalResult Create(Type objectType, object criteria, DataPortalContext context)
        {
            ChannelFactory<IExtendWcfPortal> cf = GetChannelFactory();
            IExtendWcfPortal svr = GetProxy(cf);
            WcfResponse response = null;
            ISerializationFormatter formatter = SerializationFormatterFactory.GetFormatter();
            try
            {
                response =
                  svr.Create(GetRequest(formatter, objectType, criteria, context));
                if (cf != null)
                    cf.Close();
            }
            catch
            {
                cf.Abort();
                throw;
            }
            DataPortalResult result = GetResult(formatter, response);
            Exception error = (Exception)formatter.Deserialize(response.Error);
            if (error != null)
            {
                throw error;
            }
            return result;
        }

        /// <summary>
        
/// 获取业务对象
        
/// </summary>
        
/// <param name="objectType">要获取的业务对象类型</param>
        
/// <param name="criteria">描述要获取的业务对象的Criteria对象</param>
        
/// <param name="context">
        
/// <see cref="Server.DataPortalContext" /> 要传递的DataPortal服务器的上下文
        
/// </param>
        public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
        {
            ChannelFactory<IExtendWcfPortal> cf = GetChannelFactory();
            IExtendWcfPortal svr = GetProxy(cf);
            WcfResponse response = null;
            ISerializationFormatter formatter = SerializationFormatterFactory.GetFormatter();
            try
            {
                response =
                       svr.Fetch(GetRequest(formatter, objectType, criteria, context));
                if (cf != null)
                    cf.Close();
            }
            catch
            {
                cf.Abort();
                throw;
            }
            DataPortalResult result = GetResult(formatter, response);
            Exception error = (Exception)formatter.Deserialize(response.Error);
            if (error != null)
            {
                throw error;
            }
            return result;
        }

        /// <summary>
        
/// 更新业务对象
        
/// </summary>
        
/// <param name="obj">要更新的业务对象</param>
        
/// <param name="context">
        
/// <see cref="Server.DataPortalContext" /> 要传递的DataPortal服务器的上下文
        
/// </param>
        public DataPortalResult Update(object obj, DataPortalContext context)
        {
            ChannelFactory<IExtendWcfPortal> cf = GetChannelFactory();
            IExtendWcfPortal svr = GetProxy(cf);
            WcfResponse response = null;
            ISerializationFormatter formatter = SerializationFormatterFactory.GetFormatter();
            try
            {
                response =
                      svr.Update(GetRequest(formatter, obj, context));
                if (cf != null)
                    cf.Close();
            }
            catch
            {
                cf.Abort();
                throw;
            }


            DataPortalResult result = GetResult(formatter, response);
            Exception error = (Exception)formatter.Deserialize(response.Error);
            if (error != null)
            {
                throw error;
            }
            return result;
        }

        /// <summary>
        
/// 删除业务对象
        
/// </summary>
        
/// <param name="objectType">要删除的业务对象类型</param>
        
/// <param name="criteria">描述要删除的业务对象的Criteria对象</param>
        
/// <param name="context">
        
/// <see cref="Server.DataPortalContext" /> 要传递的DataPortal服务器的上下文
        
/// </param>
        public DataPortalResult Delete(Type objectType, object criteria, DataPortalContext context)
        {
            ChannelFactory<IExtendWcfPortal> cf = GetChannelFactory();
            IExtendWcfPortal svr = GetProxy(cf);
            WcfResponse response = null;
            ISerializationFormatter formatter = SerializationFormatterFactory.GetFormatter();
            try
            {
                response =
                      svr.Delete(GetRequest(formatter, objectType, criteria, context));
                if (cf != null)
                    cf.Close();
            }
            catch
            {
                cf.Abort();
                throw;
            }
            DataPortalResult result = GetResult(formatter, response);
            Exception error = (Exception)formatter.Deserialize(response.Error);
            if (error != null)
            {
                throw error;
            }
            return result;
        }

        #endregion

        /// <summary>
        
/// 获取请求CriteriaRequest对象
        
/// </summary>
        
/// <param name="formatter">序列化器</param>
        
/// <param name="objectType">业务对象类型</param>
        
/// <param name="criteria">Criteria对象</param>
        
/// <param name="context">要发送到DataPortal的上下文对象</param>
        
/// <returns></returns>
        private CriteriaRequest GetRequest(ISerializationFormatter formatter, Type objectType, object criteria, DataPortalContext context)
        {
            CriteriaRequest request = new CriteriaRequest();
            request.ClientContext = formatter.Serialize(Csla.ApplicationContext.ClientContext);
            request.ClientCulture = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
            request.ClientUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
            request.CriteriaData = formatter.Serialize(criteria);
            request.GlobalContext = formatter.Serialize(Csla.ApplicationContext.GlobalContext);
            if (Csla.ApplicationContext.User is System.Security.Principal.WindowsPrincipal)
            {

            }
            else
            {
                request.Principal = formatter.Serialize(Csla.ApplicationContext.User);
            }
            request.TypeName = objectType.AssemblyQualifiedName;
            request = ConvertRequest(request);
            return request;
        }

        /// <summary>
        
/// 获取请求UpdateRequest对象
        
/// </summary>
        
/// <param name="formatter">序列化器</param>
        
/// <param name="obj">要更新的业务对象</param>
        
/// <param name="context">要发送到DataPortal的上下文对象</param>
        
/// <returns></returns>
        private UpdateRequest GetRequest(ISerializationFormatter formatter, object obj, DataPortalContext context)
        {
            UpdateRequest request = new UpdateRequest();
            request.ClientContext = formatter.Serialize(Csla.ApplicationContext.ClientContext);
            request.ClientCulture = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
            request.ClientUICulture = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
            request.GlobalContext = formatter.Serialize(Csla.ApplicationContext.GlobalContext);
            if (Csla.ApplicationContext.User is System.Security.Principal.WindowsPrincipal)
            {

            }
            else
            {
                request.Principal = formatter.Serialize(Csla.ApplicationContext.User);
            }
            request.ObjectData = formatter.Serialize(obj);
            request = ConvertRequest(request);
            return request;
        }

        /// <summary>
        
/// 获取DataPortalResult对象
        
/// </summary>
        
/// <param name="formatter">序列化器</param>
        
/// <param name="response">响应</param>
        
/// <returns></returns>
        private DataPortalResult GetResult(ISerializationFormatter formatter, WcfResponse response)
        {
            response = ConvertResponse(response);
            object result = formatter.Deserialize(response.ObjectData);
            ContextDictionary globalContext = (ContextDictionary)formatter.Deserialize(response.GlobalContext);
            DataPortalResult returnValue = new DataPortalResult(result, globalContext);
            return returnValue;
        }

        /// <summary>
        
/// 转换WcfResponse
        
/// </summary>
        
/// <param name="response"></param>
        
/// <returns></returns>
        
/// <remarks>默认不做转换</remarks>
        protected virtual WcfResponse ConvertResponse(WcfResponse response)
        {
            return response;
        }

        /// <summary>
        
/// 转换CriteriaRequest
        
/// </summary>
        
/// <param name="request"></param>
        
/// <returns>默认不做转换</returns>
        protected virtual CriteriaRequest ConvertRequest(CriteriaRequest request)
        {
            return request;
        }

        /// <summary>
        
/// 转换UpdateRequest
        
/// </summary>
        
/// <param name="request"></param>
        
/// <returns>默认不做转换</returns>
        protected virtual UpdateRequest ConvertRequest(UpdateRequest request)
        {
            return request;
        }


    }
}

由于我们需要远程访问DataPortal,因此,IsServerRemote属性始终为true。

为了方便快速配置,我们定义Endpoint属性。

为了能在此基础上做进一步的传送参数处理,定义了ConvertXYZ的虚方法,这样子类就可以在序列化的基础上做进一步的传输处理。

posted on 2012-09-06 19:49  jack  阅读(763)  评论(0)    收藏  举报