zoukankan      html  css  js  c++  java
  • WCF开发日志 OEA里面的WCF设计

    一、摘要

    场景: 

          最近公司的项目中用到了WCF 就想着分析OEA里的WCF设计,吸取一下高手的经验 。

    类图:

           今天在这里主要是分析OEA里的WCF设计(也叫分布式业务对象数据门户)。先看一下OEA类库

           clipboard

    二、本文大纲

           a、摘要 。

           b、本文大纲 。

           c、WCF接口设计。

           d、WCF 交互设计 。

           e、数据门户设计 。

           f、业务对象知识补充 。

    三、WCF接口设计

    关于WCF接口的相关知识可以看以前写WCF 开发日志 -- WCF契约设计

     clipboard[5]

    消息契约(MessageContract)  在 WCF 开发日志 -- WCF契约设计 有提到一点,在网上和MSDN上有更详细的说明了,这里就不详细描述了。

    WcfResponse , FetchRequest , UpdateRequest 
    上面类图对应有三个文件,其实这三个文件的内容都差不多,只是职责不同。
    clipboard[7]
    四、WCF 交互设计

    服务端实现:

     红色部分就是WCF适配到数据门户来进行与数据库交互否实现业务逻辑。
     1:  /// <summary>
     2:    /// 使1用?WCF实现的统一的数据门户
     3:    /// 
     4:    /// 标记了ConcurrencyMode.Multiple 来表示多线程进行
     5:    /// </summary>
     6:    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
     7:    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
     8:    public class WcfPortal : IWcfPortal
     9:    {
    10:        /// <summary>
    11:        /// Get an existing business object.
    12:        /// </summary>
    13:        /// <param name="request">The request parameter object.</param>
    14:        public WcfResponse Fetch(FetchRequest request)
    15:        {
    16:            OEA.Server.DataPortalFacade portal = new OEA.Server.DataPortalFacade();
    17:            object result;
    18:            try
    19:            {
    20:                result = portal.Fetch(request.ObjectType, request.Criteria, request.Context);
    21:            }
    22:            catch (Exception ex)
    23:            {
    24:                result = ex;
    25:            }
    26:            return new WcfResponse(result);
    27:        }
    28:   
    29:        /// <summary>
    30:        /// Update a business object.
    31:        /// </summary>
    32:        /// <param name="request">The request parameter object.</param>
    33:        public WcfResponse Update(UpdateRequest request)
    34:        {
    35:            OEA.Server.DataPortalFacade portal = new OEA.Server.DataPortalFacade();
    36:            object result;
    37:            try
    38:            {
    39:                result = portal.Update(request.Object, request.Context);
    40:            }
    41:            catch (Exception ex)
    42:            {
    43:                result = ex;
    44:            }
    45:            return new WcfResponse(result);
    46:        }
    47:    }
    48:   
    客服端直接使用WCF的代理类ChannelFactory实现
      1:  /// <summary>
      2:      /// Implements a data portal proxy to relay data portal
      3:      /// calls to a remote application server by using WCF.
      4:      /// </summary>
      5:      public class WcfProxy : OEA.DataPortalClient.IDataPortalProxy,IDataPortalServer
      6:      {
      7:          #region IDataPortalProxy Members
      8:   
      9:          /// <summary>
     10:          /// Gets a value indicating whether the data portal
     11:          /// is hosted on a remote server.
     12:          /// </summary>
     13:          public bool IsServerRemote
     14:          {
     15:              get { return true; }
     16:          }
     17:   
     18:          #endregion
     19:  
     20:          #region IDataPortalServer Members
     21:   
     22:          private string _endPoint = "WcfDataPortal";
     23:   
     24:          /// <summary>
     25:          /// Gets or sets the WCF endpoint used
     26:          /// to contact the server.
     27:          /// </summary>
     28:          /// <remarks>
     29:          /// The default value is WcfDataPortal.
     30:          /// </remarks>
     31:          protected string EndPoint
     32:          {
     33:              get
     34:              {
     35:                  return _endPoint;
     36:              }
     37:              set
     38:              {
     39:                  _endPoint = value;
     40:              }
     41:          }
     42:   
     43:          /// <summary>
     44:          /// Returns an instance of the channel factory
     45:          /// used by GetProxy() to create the WCF proxy
     46:          /// object.
     47:          /// </summary>
     48:          protected virtual ChannelFactory<IWcfPortal> GetChannelFactory()
     49:          {
     50:              return new ChannelFactory<IWcfPortal>(_endPoint);
     51:          }
     52:   
     53:          /// <summary>
     54:          /// Returns the WCF proxy object used for
     55:          /// communication with the data portal
     56:          /// server.
     57:          /// </summary>
     58:          /// <param name="cf">
     59:          /// The ChannelFactory created by GetChannelFactory().
     60:          /// </param>
     61:          protected virtual IWcfPortal GetProxy(ChannelFactory<IWcfPortal> cf)
     62:          {
     63:              return cf.CreateChannel();
     64:          }
     65:   
     66:          /// <summary>
     67:          /// Called by <see cref="DataPortal" /> to load an
     68:          /// existing business object.
     69:          /// </summary>
     70:          /// <param name="objectType">Type of business object to create.</param>
     71:          /// <param name="criteria">Criteria object describing business object.</param>
     72:          /// <param name="context">
     73:          /// <see cref="Server.DataPortalContext" /> object passed to the server.
     74:          /// </param>
     75:          public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
     76:          {
     77:              ChannelFactory<IWcfPortal> cf = GetChannelFactory();
     78:              IWcfPortal svr = GetProxy(cf);
     79:              WcfResponse response = null;
     80:              try
     81:              {
     82:                  response =
     83:                         svr.Fetch(new FetchRequest(objectType, criteria, context));
     84:                  if (cf != null)
     85:                      cf.Close();
     86:              }
     87:              catch
     88:              {
     89:                  cf.Abort();
     90:                  throw;
     91:              }
     92:   
     93:              object result = response.Result;
     94:              if (result is Exception)
     95:                  throw (Exception)result;
     96:              return (DataPortalResult)result;
     97:          }
     98:   
     99:          /// <summary>
    100:          /// Called by <see cref="DataPortal" /> to update a
    101:          /// business object.
    102:          /// </summary>
    103:          /// <param name="obj">The business object to update.</param>
    104:          /// <param name="context">
    105:          /// <see cref="Server.DataPortalContext" /> object passed to the server.
    106:          /// </param>
    107:          public DataPortalResult Update(object obj, DataPortalContext context)
    108:          {
    109:              ChannelFactory<IWcfPortal> cf = GetChannelFactory();
    110:              IWcfPortal svr = GetProxy(cf);
    111:              WcfResponse response = null;
    112:              try
    113:              {
    114:                  response =
    115:                        svr.Update(new UpdateRequest(obj, context));
    116:                  if (cf != null)
    117:                      cf.Close();
    118:              }
    119:              catch
    120:              {
    121:                  cf.Abort();
    122:                  throw;
    123:              }
    124:   
    125:   
    126:              object result = response.Result;
    127:              if (result is Exception)
    128:                  throw (Exception)result;
    129:              return (DataPortalResult)result;
    130:          }
    131:   
    132:          #endregion
    133:      }
    134:   
    IWcfPortal接口 和 IDataPortalServer接口 介绍  其实这两个接口都提供了 Fetch Update
     1:  /// <summary>
     2:     /// Defines the service contract for the WCF data
     3:     /// portal.
     4:     /// </summary>
     5:     [ServiceContract(Namespace = "http://ws.lhotka.net/WcfDataPortal")]
     6:     public interface IWcfPortal
     7:     {
     8:         /// <summary>
     9:         /// Get an existing business object.
    10:         /// </summary>
    11:         /// <param name="request">The request parameter object.</param>
    12:         [OperationContract]
    13:         [UseNetDataContract]
    14:         WcfResponse Fetch(FetchRequest request);
    15:   
    16:         /// <summary>
    17:         /// Update a business object.
    18:         /// </summary>
    19:         /// <param name="request">The request parameter object.</param>
    20:         [OperationContract]
    21:         [UseNetDataContract]
    22:         WcfResponse Update(UpdateRequest request);
    23:     }
    24:   
    IDataPortalServer
     1:  /// <summary>
     2:     /// Interface implemented by server-side data portal
     3:     /// components.
     4:     /// </summary>
     5:     public interface IDataPortalServer
     6:     {
     7:         /// <summary>
     8:         /// Get an existing business object.
     9:         /// </summary>
    10:         /// <param name="objectType">Type of business object to retrieve.</param>
    11:         /// <param name="criteria">Criteria object describing business object.</param>
    12:         /// <param name="context">
    13:         /// <see cref="Server.DataPortalContext" /> object passed to the server.
    14:         /// </param>
    15:         DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context);
    16:   
    17:         /// <summary>
    18:         /// Update a business object.
    19:         /// </summary>
    20:         /// <param name="obj">Business object to update.</param>
    21:         /// <param name="context">
    22:         /// <see cref="Server.DataPortalContext" /> object passed to the server.
    23:         /// </param>
    24:         DataPortalResult Update(object obj, DataPortalContext context);
    25:     }
    26:   
    事实上这两个接口都提供了 Fetch Update 都是操作数据门户的,不过一个是服务端,一个是客服端所以实现方式上也有点不同。
    五、数据门户设计
    DataPortalFacade 数据门户外观模式 也是实现IDataPortalServer接口,主要是权限的就是上下文的实现(ApplicationContext)。
    DataPortalContext 数据上下文没有实现IDataPortalServer接口
    FinalDataPortal 最终的数据门户
     1:  /// <summary>
     2:  /// Implements the server-side DataPortal as discussed
     3:  /// in Chapter 4.
     4:  /// </summary>
     5:  public class FinalDataPortal : IDataPortalServer
     6:  {
     7:      /// <summary>
     8:      /// Get an existing business object.
     9:      /// </summary>
    10:      /// <param name="objectType">Type of business object to retrieve.</param>
    11:      /// <param name="criteria">Criteria object describing business object.</param>
    12:      /// <param name="context">
    13:      /// <see cref="Server.DataPortalContext" /> object passed to the server.
    14:      /// </param>
    15:      public DataPortalResult Fetch(Type objectType, object criteria, DataPortalContext context)
    16:      {
    17:          // create an instance of the business object.
    18:          var obj = Activator.CreateInstance(objectType, true);
    19:   
    20:          MethodCaller.CallMethodIfImplemented(obj, "QueryBy", criteria);
    21:   
    22:          // return the populated business object as a result
    23:          return new DataPortalResult(obj);
    24:      }
    25:   
    26:      /// <summary>
    27:      /// Update a business object.
    28:      /// </summary>
    29:      /// <param name="obj">Business object to update.</param>
    30:      /// <param name="context">
    31:      /// <see cref="Server.DataPortalContext" /> object passed to the server.
    32:      /// </param>
    33:      public DataPortalResult Update(object obj, DataPortalContext context)
    34:      {
    35:          // tell the business object to update itself
    36:          var target = obj as Entity;
    37:          if (target != null)
    38:          {
    39:              target.SaveRoot();
    40:          }
    41:          else if (obj is Service)
    42:          {
    43:              (obj as Service).ExecuteByDataPortal();
    44:          }
    45:          else if (obj is EntityList)
    46:          {
    47:              (obj as EntityList).SaveRootList();
    48:          }
    49:          else
    50:          {
    51:              // this is an updatable collection or some other
    52:              // non-BusinessBase type of object
    53:              // tell the object to update itself
    54:              MethodCaller.CallMethodIfImplemented(obj, "DataPortal_Update");
    55:          }
    56:   
    57:          return new DataPortalResult(obj);
    58:      }
    59:  }
    60:   
    代码约定(实体列表类需要编写对应类型的 QueryBy 数据层方法完成数据访问逻辑)也就是每一个业务对象集合都的实现QueryBy方法。DataPortal_Update 在代码里没有找到不知道作者是这么实现的。纠结中........
    六、业务对象知识补充

    说起业务对象就不的不说一下业务对象的三要素了,如下来51CTO网站上的图片

    113119383

    ■ 标识(identity),是唯一区别其他对象的标志;

    ■ 状态(state),描述对象所蕴含的信息;

    ■ 行为(behavior),对象所持有的、描述对象如何被使用的方法。

    关于业务对象的理论这里有园里有一篇就将的很全面了,这里就不做补充了,大家有兴趣可以直接看作者的这篇:关于业务对象本质的思考(1)的文章。

    以下是OEA的实体对象状态抽象:

    clipboard[9]

    以下是对象状态的实现 也就是Entity.Csla.cs  类的代码了:

      1:  /// <summary>
      2:   /// 原-来′ Csla 中D的? BusinessBase 中D的?代ú码?,?都?移?动ˉ到?这a个?类à中D。£
      3:   /// </summary>
      4:   public abstract partial class Entity 
      5:   {
      6:       #region PersistenceStatus
      7:   
      8:       [NonSerialized]
      9:       private PersistenceStatus _previousStatusBeforeDeleted = PersistenceStatus.Unchanged;
     10:       private PersistenceStatus _status = PersistenceStatus.New;
     11:   
     12:       public PersistenceStatus Status
     13:       {
     14:           get { return this._status; }
     15:           set
     16:           {
     17:               if (value != this._status)
     18:               {
     19:                   if (value == PersistenceStatus.Deleted)
     20:                   {
     21:                       this._previousStatusBeforeDeleted = this._status;
     22:                   }
     23:   
     24:                   this._status = value;
     25:               }
     26:           }
     27:       }
     28:   
     29:       public bool IsNew
     30:       {
     31:           get { return this.Status == PersistenceStatus.New; }
     32:       }
     33:   
     34:       public bool IsDeleted
     35:       {
     36:           get { return this.Status == PersistenceStatus.Deleted; }
     37:       }
     38:   
     39:       public void MarkNew()
     40:       {
     41:           this.Status = PersistenceStatus.New;
     42:       }
     43:   
     44:       public void MarkDirty()
     45:       {
     46:           if (this.Status != PersistenceStatus.New)
     47:           {
     48:               this.Status = PersistenceStatus.Modified;
     49:           }
     50:       }
     51:   
     52:       public virtual void MarkDeleted()
     53:       {
     54:           this.Status = PersistenceStatus.Deleted;
     55:       }
     56:   
     57:       public void RevertDeleted()
     58:       {
     59:           this._status = this._previousStatusBeforeDeleted;
     60:       }
     61:   
     62:       protected void MarkModified()
     63:       {
     64:           if (this.Status == PersistenceStatus.Unchanged) { this.Status = PersistenceStatus.Modified; }
     65:       }
     66:   
     67:       #endregion
     68:  
     69:       #region IDirtyAware
     70:   
     88:       public virtual bool IsSelfDirty
     89:       {
     90:           get { return this.Status != PersistenceStatus.Unchanged; }
     91:       }
     92:   
     93:       public virtual void MarkOld()
     94:       {
     95:           this.Status = PersistenceStatus.Unchanged;
     96:   
     97:           foreach (var field in this.GetNonDefaultPropertyValues())
     98:           {
     99:               var value = field.Value as IDirtyAware;
    100:               if (value != null && value.IsDirty) value.MarkOld();
    101:           }
    102:       }
    103:   
    104:       #endregion
    105: 
    154:       /// <summary>
    155:       /// 这个事件不可以屏敝,否则状态会出问题
    156:       /// </summary>
    157:       /// <param name="e"></param>
    158:       protected override void OnPropertyChanged(IManagedPropertyChangedEventArgs e)
    159:       {
    160:           if (e.Source != ManagedPropertyChangedSource.FromPersistence)
    161:           {
    162:               this.MarkModified();
    163:           }
    164:   
    165:           base.OnPropertyChanged(e);
    166:       }
    167:   
    254:   }
    255:   

    在那里使用了对象状态?

    七、总结

    这里主要是学到了什么是业务对象,WCF接口设计,服务实现,代理,.NET数据上下文的实现。

    整体设计图纸:

    image

    不懂之处:DataPortal_Update没有找到,对象状态不知道在那里使用,还是说客服端传过来的?

    技术不足之处,对数据上下文的理解。

  • 相关阅读:
    Java算法练习——整数反转
    Java算法练习—— Z 字形变换
    Java算法练习——最长回文子串
    vs code自动生成html代码
    thinkphp整合后台模板
    composer安装后台模板
    composer(作曲家)安装php-ml
    两个网站
    PHP的开源产品discuz
    onethink中的用户登录session签名
  • 原文地址:https://www.cnblogs.com/luomingui/p/2685914.html
Copyright © 2011-2022 走看看