個人NopCommerce之旅(9): 編寫Plugin實例

1、基礎介紹

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

  Plugin,即插件,用來作NopCommerce的功能擴展。NopCommerce源碼自己提供了一些插件供參考使用。本篇文章經過閱讀官方文檔進行實踐總結,主要講解如何編寫一個數據持久化的NopCommerce插件。sql

2、效果展現

  當打開前臺產品詳細時,系統會自動追蹤並記錄用戶訪問的產品信息、訪問的用戶信息及其IP地址信息等。數據庫

  

3、編寫步驟

  1.新建項目,項目名爲Nop.Plugin.Other.ProductViewTracker,注意項目位置需統一放置在..\plugins\下,與輸出位置保持統一。app

  

  2.添加Description.txt文件,該文件爲必備文件,且格式需保持統一。該文件描述插件相關信息,並做爲系統識別插件依據。ide

  

  3.添加必要的文件夾,名稱可根據我的習慣,這裏爲保持命名規則統一,命名以下Controllers、Data、Domain、Services。ui

  

  4.添加dll引用,且設置屬性"Copy Local"爲False。本項目引用如圖所示。this

   

  5.添加實體類及其數據庫映射,添加數據庫訪問上下文。spa

    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>3d

 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.Web\Views\Product\ProductTemplate.Simple.cshtml中插入應用代碼。

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

  如圖

  

相關文章
相關標籤/搜索