我的NopCommerce之旅(9): 编写Plugin实例

一、基础介绍

  ——In computing, a plug-in (or plugin) is a set of software components that add specific abilities to a larger software application (Wikipedia).

  Plugin,即插件,用来做NopCommerce的功能扩展。NopCommerce源码本身提供了一些插件供参考使用。本篇文章通过阅读官方文档进行实践总结,主要讲解如何编写一个数据持久化的NopCommerce插件。

二、效果展示

  当打开前台产品详细时,系统会自动追踪并记录用户访问的产品信息、访问的用户信息及其IP地址信息等。

  

三、编写步骤

  1.新建项目,项目名为Nop.Plugin.Other.ProductViewTracker,注意项目位置需统一放置在..plugins下,与输出位置保持统一。

  

  2.添加Description.txt文件,该文件为必备文件,且格式需保持统一。该文件描述插件相关信息,并作为系统识别插件依据。

  

  3.添加必要的文件夹,名称可根据个人习惯,这里为保持命名规则统一,命名如下Controllers、Data、Domain、Services。

  

  4.添加dll引用,且设置属性"Copy Local"为False。本项目引用如图所示。

   

  5.添加实体类及其数据库映射,添加数据库访问上下文。

    5.1 实体类TrackingRecord,继承基类BaseEntity

 1 using Nop.Core;
 2 
 3 namespace Nop.Plugin.Other.ProductViewTracker.Domain
 4 {
 5     public class TrackingRecord : BaseEntity
 6     {
 7         public virtual int ProductId { get; set; }
 8         public virtual string ProductName { get; set; }
 9         public virtual int CustomerId { get; set; }
10         public virtual string IpAddress { get; set; }
11         public virtual bool IsRegistered { get; set; }
12     }
13 }

    5.2 数据库表映射类TrackingRecordMap,继承EntityTypeConfiguration<T>

 1 using Nop.Plugin.Other.ProductViewTracker.Domain;
 2 using System.Data.Entity.ModelConfiguration;
 3 
 4 namespace Nop.Plugin.Other.ProductViewTracker.Data
 5 {
 6     public class TrackingRecordMap : EntityTypeConfiguration<TrackingRecord>
 7     {
 8         public TrackingRecordMap()
 9         {
10             ToTable("ProductViewTracking");
11 
12             HasKey(m => m.Id);
13             Property(m => m.ProductId);
14             Property(m => m.ProductName).HasMaxLength(400);
15             Property(m => m.IpAddress);
16             Property(m => m.CustomerId);
17             Property(m => m.IsRegistered);
18         }
19     }
20 }

    5.3 数据库访问上下文,安装插件时生成并执行建表脚本,卸载插件时删除该表

 1 using Nop.Data;
 2 using System;
 3 using System.Collections.Generic;
 4 using System.Data.Entity;
 5 using Nop.Core;
 6 using System.Data.Entity.Infrastructure;
 7 
 8 namespace Nop.Plugin.Other.ProductViewTracker.Data
 9 {
10     public class TrackingRecordObjectContext : DbContext, IDbContext
11     {
12         public TrackingRecordObjectContext(string nameOrConnectionString) : base(nameOrConnectionString) { }
13 
14         #region Implementation of IDbContext
15 
16         public bool AutoDetectChangesEnabled
17         {
18             get
19             {
20                 throw new NotImplementedException();
21             }
22 
23             set
24             {
25                 throw new NotImplementedException();
26             }
27         }
28 
29         public bool ProxyCreationEnabled
30         {
31             get
32             {
33                 throw new NotImplementedException();
34             }
35 
36             set
37             {
38                 throw new NotImplementedException();
39             }
40         }
41 
42         public void Detach(object entity)
43         {
44             throw new NotImplementedException();
45         }
46 
47         public int ExecuteSqlCommand(string sql, bool doNotEnsureTransaction = false, int? timeout = default(int?), params object[] parameters)
48         {
49             throw new NotImplementedException();
50         }
51 
52         public IList<TEntity> ExecuteStoredProcedureList<TEntity>(string commandText, params object[] parameters) where TEntity : BaseEntity, new()
53         {
54             throw new NotImplementedException();
55         }
56 
57         public IEnumerable<TElement> SqlQuery<TElement>(string sql, params object[] parameters)
58         {
59             throw new NotImplementedException();
60         }
61 
62         public new IDbSet<TEntity> Set<TEntity>() where TEntity : BaseEntity
63         {
64             return base.Set<TEntity>();
65         }
66 
67         protected override void OnModelCreating(DbModelBuilder modelBuilder)
68         {
69             modelBuilder.Configurations.Add(new TrackingRecordMap());
70 
71             base.OnModelCreating(modelBuilder);
72         }
73 
74         #endregion
75 
76         public string CreateDatabaseInstallationScript()
77         {
78             return ((IObjectContextAdapter)this).ObjectContext.CreateDatabaseScript();
79         }
80 
81         public void Install()
82         {
83             Database.SetInitializer<TrackingRecordObjectContext>(null);
84 
85             Database.ExecuteSqlCommand(CreateDatabaseInstallationScript());
86             SaveChanges();
87         }
88 
89         public void Uninstall()
90         {
91             var dbScript = "DROP TABLE ProductViewTracking";
92             Database.ExecuteSqlCommand(dbScript);
93             SaveChanges();
94         }
95     }
96 }

  6.添加业务服务类。

    6.1 服务接口

 1 using Nop.Plugin.Other.ProductViewTracker.Domain;
 2 
 3 namespace Nop.Plugin.Other.ProductViewTracker.Services
 4 {
 5     public interface IViewTrackingService
 6     {
 7         /// <summary>
 8         /// Logs the specified record.
 9         /// </summary>
10         /// <param name="record">The record.</param>
11         void Log(TrackingRecord record);
12     }
13 }

    6.2 业务服务类

 1 using Nop.Core.Data;
 2 using Nop.Plugin.Other.ProductViewTracker.Domain;
 3 
 4 namespace Nop.Plugin.Other.ProductViewTracker.Services
 5 {
 6     public class ViewTrackingService : IViewTrackingService
 7     {
 8         private readonly IRepository<TrackingRecord> _trackingRecordRepository;
 9 
10         public ViewTrackingService(IRepository<TrackingRecord> trackingRecordRepository)
11         {
12             _trackingRecordRepository = trackingRecordRepository;
13         }
14 
15         public void Log(TrackingRecord record)
16         {
17             _trackingRecordRepository.Insert(record);
18         }
19     }
20 }

  7.实现依赖注入的注册接口。

 1 using Nop.Core.Infrastructure.DependencyManagement;
 2 using Autofac;
 3 using Nop.Core.Configuration;
 4 using Nop.Core.Infrastructure;
 5 using Nop.Plugin.Other.ProductViewTracker.Services;
 6 using Nop.Web.Framework.Mvc;
 7 using Nop.Plugin.Other.ProductViewTracker.Data;
 8 using Nop.Data;
 9 using Nop.Plugin.Other.ProductViewTracker.Domain;
10 using Nop.Core.Data;
11 using Autofac.Core;
12 
13 namespace Nop.Plugin.Other.ProductViewTracker
14 {
15     public class DependencyRegistrar : IDependencyRegistrar
16     {
17         private const string CONTEXT_NAME = "nop_object_context_product_view_tracker";
18 
19         public void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config)
20         {
21             builder.RegisterType<ViewTrackingService>().As<IViewTrackingService>().InstancePerLifetimeScope();
22 
23             //data context
24             this.RegisterPluginDataContext<TrackingRecordObjectContext>(builder, CONTEXT_NAME);
25 
26             //override required repository with our custom context
27             builder.RegisterType<EfRepository<TrackingRecord>>()
28                 .As<IRepository<TrackingRecord>>()
29                 .WithParameter(ResolvedParameter.ForNamed<IDbContext>(CONTEXT_NAME))
30                 .InstancePerLifetimeScope();
31         }
32 
33         public int Order
34         {
35             get { return 1; }
36         }
37     }
38 }

  8.添加MVC Controller。

 1 using Nop.Core;
 2 using Nop.Core.Domain.Catalog;
 3 using Nop.Core.Domain.Customers;
 4 using Nop.Core.Plugins;
 5 using Nop.Plugin.Other.ProductViewTracker.Domain;
 6 using Nop.Plugin.Other.ProductViewTracker.Services;
 7 using Nop.Services.Catalog;
 8 using Nop.Web.Framework.Controllers;
 9 using System.Web.Mvc;
10 
11 namespace Nop.Plugin.Other.ProductViewTracker.Controllers
12 {
13     public class TrackingController : BasePluginController
14     {
15         private readonly IProductService _productService;
16         private readonly IViewTrackingService _viewTrackingService;
17         private readonly IWorkContext _workContext;
18 
19         public TrackingController(IWorkContext workContext,
20             IViewTrackingService viewTrackingService,
21             IProductService productService,
22             IPluginFinder pluginFinder)
23         {
24             _workContext = workContext;
25             _viewTrackingService = viewTrackingService;
26             _productService = productService;
27         }
28 
29         [ChildActionOnly]
30         public ActionResult Index(int productId)
31         {
32             //Read from the product service
33             Product productById = _productService.GetProductById(productId);
34 
35             //If the product exists we will log it
36             if (productById != null)
37             {
38                 //Setup the product to save
39                 var record = new TrackingRecord();
40                 record.ProductId = productId;
41                 record.ProductName = productById.Name;
42                 record.CustomerId = _workContext.CurrentCustomer.Id;
43                 record.IpAddress = _workContext.CurrentCustomer.LastIpAddress;
44                 record.IsRegistered = _workContext.CurrentCustomer.IsRegistered();
45 
46                 //Map the values we're interested in to our new entity
47                 _viewTrackingService.Log(record);
48             }
49 
50             //Return the view, it doesn't need a model
51             return Content("");
52         }
53     }
54 }

  9.实现路由接口。

 1 using Nop.Web.Framework.Mvc.Routes;
 2 using System.Web.Mvc;
 3 using System.Web.Routing;
 4 
 5 namespace Nop.Plugin.Other.ProductViewTracker
 6 {
 7     public class RouteProvider : IRouteProvider
 8     {
 9         public int Priority
10         {
11             get
12             {
13                 return 0;
14             }
15         }
16 
17         public void RegisterRoutes(RouteCollection routes)
18         {
19             routes.MapRoute("Nop.Plugin.Other.ProductViewTracker.Log",
20                  "tracking/productviews/{productId}",
21                  new { controller = "Tracking", action = "Index" },
22                  new[] { "Nop.Plugin.Other.ProductViewTracker.Controllers" }
23             );
24         }
25     }
26 }

  10.添加插件类,继承插件基类,重载安装和卸载方法。

 1 using Nop.Core.Plugins;
 2 using Nop.Plugin.Other.ProductViewTracker.Data;
 3 
 4 namespace Nop.Plugin.Other.ProductViewTracker
 5 {
 6     public class ProductViewTrackerPlugin : BasePlugin
 7     {
 8         private readonly TrackingRecordObjectContext _context;
 9 
10         public ProductViewTrackerPlugin(TrackingRecordObjectContext context)
11         {
12             _context = context;
13         }
14 
15         public override void Install()
16         {
17             _context.Install();
18             base.Install();
19         }
20 
21         public override void Uninstall()
22         {
23             _context.Uninstall();
24             base.Uninstall();
25         }
26     }
27 }

  11.在NopCommerce的前台,加入插件的应用代码。这里,我们在页面Nop.WebViewsProductProductTemplate.Simple.cshtml中插入应用代码。

@Html.Action("Index", "Tracking", new { productId = Model.Id })

  如图

  

原文地址:https://www.cnblogs.com/devilsky/p/5376401.html