前台网站开发手记

前台网站开发手记
已CustomerRank开发为例:
首先看数据库表结构:
SELECT TOP 1000 [ID]
  ,[CreatedAt]
  ,[CreatorID]
  ,[Name]
  ,[Type]
  ,[FloorAmount]
  ,[CeilingAmount]
  ,[DiscountPercent]
  ,[CanUse]
  ,[Enabled]
  ,[LastModifiedAt]
  ,[LastModifierID]
FROM [Infrastructures].[Infrastructures].[CustomerRanks]
可以看出来是[Infrastructures]架构的一部分,所以该数据的Model就建立在DBC.Ors.UI.Shop.Core中的Models/Infrastructures的文件夹里面命名为CustomerRankVM,注意后缀VM,表示ViewModel,Model中的字段名称必须和数据库表字段名称一样,用不到的字段可以不用写在Model中。
[ID],[CreatedAt],[CreatorID],[LastModifiedAt],[LastModifierID]这五个字段是在每一张表中都有的字段,我们抽象出来写在AbstractModel中,我们定义CustomerRankVM继承AbstractModel,我们前台以后要用的字段是:[Name],[Type],[CanUse] ,[Enabled],所以定义Model为:
[Serializable]
public class CustomerRankVM : AbstractModel
{
    /// <summary>
    /// 会员等级名称
    /// </summary>
    public string Name { get; set; }
    /// <summary>
    /// 会员等级类型
    /// </summary>
    public int? Type { get; set; }
    /// <summary>
    /// 折扣率
    /// </summary>
    public decimal? DiscountPercent { get; set; }
    /// <summary>
    /// 等级对应的限制(是否能获得优惠0x1/是否能使用积分0x2)
    /// </summary>
    public int? CanUse { get; set; }
    /// <summary>
    /// 是否有效
    /// </summary>
    public bool? Enabled { get; set; }
}
注意加上[Serializable]特性,以后我们使用Memcache缓存数据,Memcache只能缓存具有[Serializable]特性的对象。                
一般我们定义一个Model的时候,还需要定义另外两个辅助Model:
public class CustomerRankVMQuery : AbstractQuery<CustomerRankVM>
{
    public long? Type { get; set; }
    public bool? Enabled { get; set; }
}

[Serializable]
public class CustomerRankCacheModel : AbstractCacheModel
{
    public IEnumerable<CustomerRankVM> CustomerRankList { get; set; }
}
一个是CustomerRank的查询对象,一个是CustomerRank的缓存对象。注意缓存对象也要加上[Serializable]特性。
数据库表和对应的Model建立好了,我们就对它们添加一个映射,因为是Infrastructures架构下,所以在Components/InfrastructuresDbContext文件中添加:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<CustomerRankVM>().ToTable("CustomerRanks", "Infrastructures");//会员等级信息
}
数据实体已经建立完成,下面一步就是缓存机制的建立。
我们使用memcached.exe缓存,首先建立memcached缓存服务:
sc delete Memcachedserver11211删除现有的服务
sc create Memcachedserver11211 binpath= "E:\memcahced\memcached.exe -d runservice -m 1024 -p 11211" start= auto displayname= "Memcached server (11211)"新建服务,使用services.msc查看服务的情况。
然后在配置文件里面配置:
<?xml version="1.0" encoding="utf-8" ?>
<memcached-configuration xmlns="urn:memcached-configuration">
  <master>
    <memcached>       
      <server address="127.0.0.1" port="11211" />
      <socket-pool minPoolSize="10" maxPoolSize="999" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
    </memcached>
  </master>
</memcached-configuration>

那下面就开始帮助CustomerRank建立缓存,增加网站的性能。
在CacheKeyConfig中增加缓存Key:
public const string CustomerRankCache = "CustomerRankCache";
还要在数据库中:[Mall].[Mall].[DBCConfigs]表中增加一条记录,字段有:[ID],[DbcKey],[DbcValue],[Description],[CreatedAt],[CreatorID],[LastModifiedAt],[LastModifierID],[Deleted],ID是表的主键,DbcKey是缓存的Key值,DbcValue是缓存的分钟数,一般是20,Deleted是指是否删除。
在Cache/Infrastructures中添加CustomerRankCache:
public class CustomerRankCache
{
    #region 缓存会员等级信息

    public void Set(IEnumerable<CustomerRankVM> list)
    {
        MemcacheDictionary<CustomerRankCacheModel> cache = new MemcacheDictionary<CustomerRankCacheModel>();
        CustomerRankCacheModel model = new CustomerRankCacheModel { CacheTime = DateTime.Now, CustomerRankList = list };
        cache.Set(CacheKeyConfig.CustomerRankCache, "", model);
    }

    #endregion

    #region 获取会员等级信息

    public CustomerRankVM Get(int id)
    {
        var svc = ServiceLocator.Resolve<IModelService>();
        CustomerRankVMQuery query = new CustomerRankVMQuery() { Enabled = true };
        var data = svc.SelectOrEmpty(query);
        if (data.Any())
        {
            return data.FirstOrDefault(p => p.ID == id);
        }
        return null;
    }

    #endregion
}
Set是保存缓存的方法,Get是读取数据库数据的方法,这里并没有读取缓存中的数据,我们现在可以对Get方法中的svc.SelectOrEmpty(query)进行拦截,在拦截中进行使用缓存等操作。
模型在Models文件夹中,缓存在Cache文件夹中,数据库和Model映射在Components文件夹中,那拦截是在Modules文件夹中。
在Modules\Infrastructures中添加CustomerRankRepository.cs文件:
public partial class InfrastructuresRepository
{
    #region 会员等级信息查询事件

    public ModelQueryEvent<CustomerRankVM> OnCustomerRankQuery(ModelQueryEvent<CustomerRankVM> eventData,
                                                                CallNext<ModelQueryEvent<CustomerRankVM>> callnext)
    {
        var query = eventData.Query;
        if (query == null)
            throw new ArgumentNullException("eventData.Query");

        #region 第一步从缓存中读取数据

        MemcacheDictionary<CustomerRankCacheModel> cache = new MemcacheDictionary<CustomerRankCacheModel>();
        var data = cache.Get(CacheKeyConfig.CustomerRankCache);


        #endregion

        #region 第二步判断是否有缓存,如果缓存中没有信息,就更新缓存信息

        if (data == null || data.CustomerRankList == null || !data.CustomerRankList.Any())
        {
            eventData = callnext(eventData);
            if (eventData.ReturnValue != null && eventData.ReturnValue.Any())
            {
                SingletonProvider<CustomerRankCache>.Instance.Set(eventData.ReturnValue);
            }
        }
        else
        {
            eventData.ReturnValue = data.CustomerRankList;
            SingletonProvider<ValidateRefreshCache>.Instance.ValidateCache(() =>
                {
                    SingletonProvider<CustomerRankCache>.Instance.Set(eventData.ReturnValue);

                }, CacheKeyConfig.CustomerRankCache, "", data.CacheTime);
        }

        #endregion

        return eventData;
    }

    #endregion
}
类名称是partial class InfrastructuresRepository,我们一般是通过目录去找对应的功能,Modules\Infrastructures\CustomerRankRepository.cs文件,我们一眼就可以看出来是CustomerRank功能模块的,里面定义partial class InfrastructuresRepository是因为每一个大的架构做成一个拦截类,因为每一个拦截类都需要在配置文件里面配置,要是每一个小模块都有自己的拦截类那么在配置文件中将会有数不清的拦截类的配置。所以控制拦截类的数量是很关键的,我们通过上面的手段,可以对不同功能使用不同的目录,但是却都是属于InfrastructuresRepository类的。
实现好拦截事件后,还要把这个实现的事件,添加到监听者,这样才会在即将促发的时候调用所以观察者,添加监听:
public partial class InfrastructuresRepository : EventSubscriber
{
    protected override void InitializeComponents()
    {
        #region Area

        this.AddEventListener<ModelQueryEvent<AreaVM>>(new Events.Listener<ModelQueryEvent<AreaVM>>(this.OnAreaQuery));
        this.AddEventListener<ModelActionEvent<Area>>(new Events.Listener<ModelActionEvent<Area>>(this.UpdateCacheOnAreaChange));

        #endregion

        #region Categories

        this.AddEventListener<ModelQueryEvent<CategoryVM>>(new Events.Listener<ModelQueryEvent<CategoryVM>>(this.OnCategoryQuery));
        this.AddEventListener<ModelActionEvent<Category>>(new Events.Listener<ModelActionEvent<Category>>(this.UpdateCacheOnCategoryChange));

        #endregion

        #region Customerrank

        this.AddEventListener<ModelQueryEvent<CustomerRankVM>>(new Events.Listener<ModelQueryEvent<CustomerRankVM>>(this.OnCustomerRankQuery));

        #endregion
    }
}
最后还要把这个模块的统一的Module:InfrastructuresRepository类配置到配置文件中,让ModuleManager管理:
<!-- 模块管理 -->
<register type="IModuleManager" mapTo="DBC.Modules.ModuleManager, DBC.Core">
<method name="Initialize">
  <param name="modules">
    <array>              
      <dependency name="MallRepository" />
      <dependency name="Mall_Persistency" />
      <dependency name="ProductionRepository" />
      <dependency name="Production_Persistency" />
      <dependency name="InfrastructuresRepository" />
      <!--<dependency name="Test" />-->
      <dependency name="Persistency"/>
      <dependency name="Job"/>
      <!-- Web Service客户端 管理员身份 -->
      <dependency name="Web_Service_Client_Internal" />
      <!-- Web Service客户端 -->
      <dependency name="Web_Service_Client" />
    </array>
  </param>
</method>
</register>

完成上面所有的步骤,那我们完成的服务接口就算是完成好了,我们在Controller中调用,测试接口:
public class HomeController : Controller
{
    public ActionResult Index()
    {
        var customerRank = SingletonProvider<CustomerRankCache>.Instance.Get(1);
        ViewBag.Message = "欢迎使用 ASP.NET MVC!";
        return View();
    }
}

这样前台网站开发的示例就结束了。






posted @ 2013-04-01 08:46  八神吻你  阅读(555)  评论(0编辑  收藏  举报