一.基础介绍

nop支持多店及多语言,本篇结合NivoSlider插件介绍下如何开发支持多商城的小部件。

主要接口如下:

ISettingService 接口:设置接口,可实现多店配置。

ILocalizationService 接口:本地化资源接口,配合语言,实现多语言的显示。

二.插件安装、卸载

我们在上一篇介绍了小部件如何使用(点击这里),这里介绍下如何安装、卸载插件。

【后台管理】【插件管理】【本地插件】可以对插件进行安装、卸载

Nop.Admin.Controllers.PluginController控制器用于插件的管理。Install负责安装插件、Uninstall负责卸载插件。

所有插件都继承IPlugin接口,Install(),Uninstall()分别用于安装及卸载。

 namespace Nop.Core.Plugins
{
/// <summary>
/// Interface denoting plug-in attributes that are displayed throughout
/// the editing interface.
/// </summary>
public interface IPlugin
{
/// <summary>
/// Gets or sets the plugin descriptor
/// </summary>
PluginDescriptor PluginDescriptor { get; set; } /// <summary>
/// Install plugin
/// </summary>
void Install(); /// <summary>
/// Uninstall plugin
/// </summary>
void Uninstall();
}
}

BasePlugin抽象类继承了IPlugin接口,并实现了 Install(),Uninstall()方法,当安装时在"~/App_Data/InstalledPlugins.txt"文件中写入插件的SystemName,卸载时则在文件中删除。

 namespace Nop.Core.Plugins
{
/// <summary>
/// Base plugin
/// </summary>
public abstract class BasePlugin : IPlugin
{
/// <summary>
/// Gets or sets the plugin descriptor
/// </summary>
public virtual PluginDescriptor PluginDescriptor { get; set; } /// <summary>
/// Install plugin
/// </summary>
public virtual void Install()
{
PluginManager.MarkPluginAsInstalled(this.PluginDescriptor.SystemName);
} /// <summary>
/// Uninstall plugin
/// </summary>
public virtual void Uninstall()
{
PluginManager.MarkPluginAsUninstalled(this.PluginDescriptor.SystemName);
} }
}

我们看下NivoSlider插件在安装时都做了哪些操作。

 using System.Collections.Generic;
using System.IO;
using System.Web.Routing;
using Nop.Core;
using Nop.Core.Plugins;
using Nop.Services.Cms;
using Nop.Services.Configuration;
using Nop.Services.Localization;
using Nop.Services.Media; namespace Nop.Plugin.Widgets.NivoSlider
{
/// <summary>
/// PLugin
/// </summary>
public class NivoSliderPlugin : BasePlugin, IWidgetPlugin
{
private readonly IPictureService _pictureService;
private readonly ISettingService _settingService;
private readonly IWebHelper _webHelper; public NivoSliderPlugin(IPictureService pictureService,
ISettingService settingService, IWebHelper webHelper)
{
this._pictureService = pictureService;
this._settingService = settingService;
this._webHelper = webHelper;
} /// <summary>
/// Gets widget zones where this widget should be rendered
/// </summary>
/// <returns>Widget zones</returns>
public IList<string> GetWidgetZones()
{
return new List<string> { "home_page_top" };
} /// <summary>
/// Gets a route for provider configuration
/// </summary>
/// <param name="actionName">Action name</param>
/// <param name="controllerName">Controller name</param>
/// <param name="routeValues">Route values</param>
public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues)
{
actionName = "Configure";
controllerName = "WidgetsNivoSlider";
routeValues = new RouteValueDictionary { { "Namespaces", "Nop.Plugin.Widgets.NivoSlider.Controllers" }, { "area", null } };
} /// <summary>
/// Gets a route for displaying widget
/// </summary>
/// <param name="widgetZone">Widget zone where it's displayed</param>
/// <param name="actionName">Action name</param>
/// <param name="controllerName">Controller name</param>
/// <param name="routeValues">Route values</param>
public void GetDisplayWidgetRoute(string widgetZone, out string actionName, out string controllerName, out RouteValueDictionary routeValues)
{
actionName = "PublicInfo";
controllerName = "WidgetsNivoSlider";
routeValues = new RouteValueDictionary
{
{"Namespaces", "Nop.Plugin.Widgets.NivoSlider.Controllers"},
{"area", null},
{"widgetZone", widgetZone}
};
} /// <summary>
/// Install plugin
/// </summary>
public override void Install()
{
//pictures
var sampleImagesPath = CommonHelper.MapPath("~/Plugins/Widgets.NivoSlider/Content/nivoslider/sample-images/"); //settings
var settings = new NivoSliderSettings
{
Picture1Id = _pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "banner1.jpg"), MimeTypes.ImagePJpeg, "banner_1").Id,
Text1 = "",
Link1 = _webHelper.GetStoreLocation(false),
Picture2Id = _pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "banner2.jpg"), MimeTypes.ImagePJpeg, "banner_2").Id,
Text2 = "",
Link2 = _webHelper.GetStoreLocation(false),
//Picture3Id = _pictureService.InsertPicture(File.ReadAllBytes(sampleImagesPath + "banner3.jpg"), MimeTypes.ImagePJpeg, "banner_3").Id,
//Text3 = "",
//Link3 = _webHelper.GetStoreLocation(false),
};
_settingService.SaveSetting(settings); this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture1", "Picture 1");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture2", "Picture 2");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture3", "Picture 3");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture4", "Picture 4");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture5", "Picture 5");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture", "Picture");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture.Hint", "Upload picture.");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Text", "Comment");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Text.Hint", "Enter comment for picture. Leave empty if you don't want to display any text.");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Link", "URL");
this.AddOrUpdatePluginLocaleResource("Plugins.Widgets.NivoSlider.Link.Hint", "Enter URL. Leave empty if you don't want this picture to be clickable."); base.Install();
} /// <summary>
/// Uninstall plugin
/// </summary>
public override void Uninstall()
{
//settings
_settingService.DeleteSetting<NivoSliderSettings>(); //locales
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture1");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture2");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture3");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture4");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture5");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Picture.Hint");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Text");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Text.Hint");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Link");
this.DeletePluginLocaleResource("Plugins.Widgets.NivoSlider.Link.Hint"); base.Uninstall();
}
}
}

Nop.Plugin.Widgets.NivoSlider

在上边源代码中我们看到安装时调用Install()方法进行了如下操作

1.定义NivoSliderSettings类,该类继承ISettings,用于保存幻灯片的配置。将初始化的配置保存到数据库Setting表中。

2.this.AddOrUpdatePluginLocaleResource方法添加本地资源,主要用于配置资源在多语言支持。

3.base.Install() 进行插件安装。

卸载插件时调用Uninstall()方法对配置进行删除,对本地资源进行删除同时卸载插件。

以上就是在插件安装、卸载时调用的方法介绍,在二次开发时可在相关时间点进行插件的配置。

三.插件配置路由

不同插件有属于自己的配置项,例如支付宝插件和微信支付插件同是支付插件但是配置却不一样。为了实现不同配置引入了配置路由。小部件IWidgetPlugin接口GetConfigurationRoute方法用于返回配置接口的路由信息。我们看下NivoSlider插件

    /// <summary>
/// Gets a route for provider configuration
/// </summary>
/// <param name="actionName">Action name</param>
/// <param name="controllerName">Controller name</param>
/// <param name="routeValues">Route values</param>
public void GetConfigurationRoute(out string actionName, out string controllerName, out RouteValueDictionary routeValues)
{
actionName = "Configure";
controllerName = "WidgetsNivoSlider";
routeValues = new RouteValueDictionary { { "Namespaces", "Nop.Plugin.Widgets.NivoSlider.Controllers" }, { "area", null } };
}

当点击配置时路由到WidgetsNivoSlider控制器Configure()方法,显示插件配置页面

四.多店配置实现

如果配置了两个以上的商城就会出现上边的多店设置。可针对不同商店进行不同的配置。

 [AdminAuthorize]
[ChildActionOnly]
public ActionResult Configure()
{
//加载可用商店的范围
var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
var nivoSliderSettings = _settingService.LoadSetting<NivoSliderSettings>(storeScope);//加载可用商店的配置
var model = new ConfigurationModel();
model.Picture1Id = nivoSliderSettings.Picture1Id;
model.Text1 = nivoSliderSettings.Text1;
model.Link1 = nivoSliderSettings.Link1;
model.Picture2Id = nivoSliderSettings.Picture2Id;
model.Text2 = nivoSliderSettings.Text2;
model.Link2 = nivoSliderSettings.Link2;
model.Picture3Id = nivoSliderSettings.Picture3Id;
model.Text3 = nivoSliderSettings.Text3;
model.Link3 = nivoSliderSettings.Link3;
model.Picture4Id = nivoSliderSettings.Picture4Id;
model.Text4 = nivoSliderSettings.Text4;
model.Link4 = nivoSliderSettings.Link4;
model.Picture5Id = nivoSliderSettings.Picture5Id;
model.Text5 = nivoSliderSettings.Text5;
model.Link5 = nivoSliderSettings.Link5;
model.ActiveStoreScopeConfiguration = storeScope;
if (storeScope > 0)
{
model.Picture1Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture1Id, storeScope);
model.Text1_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text1, storeScope);
model.Link1_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link1, storeScope);
model.Picture2Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture2Id, storeScope);
model.Text2_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text2, storeScope);
model.Link2_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link2, storeScope);
model.Picture3Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture3Id, storeScope);
model.Text3_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text3, storeScope);
model.Link3_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link3, storeScope);
model.Picture4Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture4Id, storeScope);
model.Text4_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text4, storeScope);
model.Link4_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link4, storeScope);
model.Picture5Id_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Picture5Id, storeScope);
model.Text5_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Text5, storeScope);
model.Link5_OverrideForStore = _settingService.SettingExists(nivoSliderSettings, x => x.Link5, storeScope);
} return View("~/Plugins/Widgets.NivoSlider/Views/Configure.cshtml", model);
}

配置源码

查看源码我们会发现这两句是控制多店配置的

  //加载可用商店的范围
var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
var nivoSliderSettings = _settingService.LoadSetting<NivoSliderSettings>(storeScope);//加载可用商店的配置

首先加载当前配置的商店。获取到 storeScope后加载该商店NivoSliderSetting配置项的设置。

这样当选择不同的商城就可以获取到选择商城中配置的值了。

我们再来看下Configure.cshtml视图

@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" })

该路由用于生成nop多店设置模块,选择不同商城会调用Setting控制器,ChangeStoreScopeConfiguration方法,该方法会将用户选择的商城id 保存在GenericaAttribute表中如下图。

SystemCustomerAttributeNames.AdminAreaStoreScopeConfiguration变量对应的就是Key值,Velue保存为商城的Id。

当页面选择不同的商城时,经过上边方法的处理,再调用var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext); 方法就可以获取到指定的商城了。

当指定商城时我们会发现配置项每一项都多出一个单选框,选择则可针对该商城的该配置经进行设置,如果不选择则使用默认项。

在视图中如何生成这个单选项呢?看下源码

@Html.OverrideStoreCheckboxFor(model => model.Picture2Id_OverrideForStore, model => model.Picture2Id, Model.ActiveStoreScopeConfiguration)

使用该Html扩展来实现商城配置的定制。OverrideStoreCheckboxFor扩展是Nop.Web.Framework.HtmlExtensions 类中的扩展。

model.Picture2Id_OverrideForStore为True时使用自定义商城配置,model.Picture2Id为配置属性,model.ActiveStoreScopeConfiguration为当前商城id。

可以看出支持多店配置的model比普通model多出ActiveStoreScopeConfiguration属性用于保存商城id,同时每个属性多一个_OverrideForStore的bool方法用于判断是否覆盖店铺默认值。

 @{
Layout = "";
}
@model Nop.Plugin.Widgets.NivoSlider.Models.ConfigurationModel
@using Nop.Web.Framework; @Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" }) @using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading">
@T("Plugins.Widgets.NivoSlider.Picture1")
</div>
<div class="panel-body">
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Picture1Id_OverrideForStore, model => model.Picture1Id, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Picture1Id)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Picture1Id)
@Html.ValidationMessageFor(model => model.Picture1Id)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Text1_OverrideForStore, model => model.Text1, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Text1)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Text1)
@Html.ValidationMessageFor(model => model.Text1)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Link1_OverrideForStore, model => model.Link1, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Link1)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Link1)
@Html.ValidationMessageFor(model => model.Link1)
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
@T("Plugins.Widgets.NivoSlider.Picture2")
</div>
<div class="panel-body">
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Picture2Id_OverrideForStore, model => model.Picture2Id, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Picture2Id)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Picture2Id)
@Html.ValidationMessageFor(model => model.Picture2Id)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Text2_OverrideForStore, model => model.Text2, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Text2)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Text2)
@Html.ValidationMessageFor(model => model.Text2)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Link2_OverrideForStore, model => model.Link2, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Link2)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Link2)
@Html.ValidationMessageFor(model => model.Link2)
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
@T("Plugins.Widgets.NivoSlider.Picture3")
</div>
<div class="panel-body">
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Picture3Id_OverrideForStore, model => model.Picture3Id, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Picture3Id)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Picture3Id)
@Html.ValidationMessageFor(model => model.Picture3Id)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Text3_OverrideForStore, model => model.Text3, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Text3)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Text3)
@Html.ValidationMessageFor(model => model.Text3)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Link3_OverrideForStore, model => model.Link3, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Link3)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Link3)
@Html.ValidationMessageFor(model => model.Link3)
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
@T("Plugins.Widgets.NivoSlider.Picture4")
</div>
<div class="panel-body">
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Picture4Id_OverrideForStore, model => model.Picture4Id, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Picture4Id)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Picture4Id)
@Html.ValidationMessageFor(model => model.Picture4Id)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Text4_OverrideForStore, model => model.Text4, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Text4)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Text4)
@Html.ValidationMessageFor(model => model.Text4)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Link4_OverrideForStore, model => model.Link4, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Link4)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Link4)
@Html.ValidationMessageFor(model => model.Link4)
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
@T("Plugins.Widgets.NivoSlider.Picture5")
</div>
<div class="panel-body">
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Picture5Id_OverrideForStore, model => model.Picture5Id, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Picture5Id)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Picture5Id)
@Html.ValidationMessageFor(model => model.Picture5Id)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Text5_OverrideForStore, model => model.Text5, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Text5)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Text5)
@Html.ValidationMessageFor(model => model.Text5)
</div>
</div>
<div class="form-group">
<div class="col-md-3">
@Html.OverrideStoreCheckboxFor(model => model.Link5_OverrideForStore, model => model.Link5, Model.ActiveStoreScopeConfiguration)
@Html.NopLabelFor(model => model.Link5)
</div>
<div class="col-md-9">
@Html.NopEditorFor(model => model.Link5)
@Html.ValidationMessageFor(model => model.Link5)
</div>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-body">
<div class="form-group">
<div class="col-md-3">
&nbsp;
</div>
<div class="col-md-9">
<input type="submit" name="save" class="btn bg-blue" value="@T("Admin.Common.Save")" />
</div>
</div>
</div>
</div>
</div>
}

配置视图代码

提交配置时会调用_settingService.SaveSettingOverridablePerStore方法,用于保存配置对多店的支持。

   [HttpPost]
[AdminAuthorize]
[ChildActionOnly]
public ActionResult Configure(ConfigurationModel model)
{
//load settings for a chosen store scope
var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);
var nivoSliderSettings = _settingService.LoadSetting<NivoSliderSettings>(storeScope); //get previous picture identifiers
var previousPictureIds = new[]
{
nivoSliderSettings.Picture1Id,
nivoSliderSettings.Picture2Id,
nivoSliderSettings.Picture3Id,
nivoSliderSettings.Picture4Id,
nivoSliderSettings.Picture5Id
}; nivoSliderSettings.Picture1Id = model.Picture1Id;
nivoSliderSettings.Text1 = model.Text1;
nivoSliderSettings.Link1 = model.Link1;
nivoSliderSettings.Picture2Id = model.Picture2Id;
nivoSliderSettings.Text2 = model.Text2;
nivoSliderSettings.Link2 = model.Link2;
nivoSliderSettings.Picture3Id = model.Picture3Id;
nivoSliderSettings.Text3 = model.Text3;
nivoSliderSettings.Link3 = model.Link3;
nivoSliderSettings.Picture4Id = model.Picture4Id;
nivoSliderSettings.Text4 = model.Text4;
nivoSliderSettings.Link4 = model.Link4;
nivoSliderSettings.Picture5Id = model.Picture5Id;
nivoSliderSettings.Text5 = model.Text5;
nivoSliderSettings.Link5 = model.Link5; /* We do not clear cache after each setting update.
* This behavior can increase performance because cached settings will not be cleared
* and loaded from database after each update */
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Picture1Id, model.Picture1Id_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Text1, model.Text1_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Link1, model.Link1_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Picture2Id, model.Picture2Id_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Text2, model.Text2_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Link2, model.Link2_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Picture3Id, model.Picture3Id_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Text3, model.Text3_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Link3, model.Link3_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Picture4Id, model.Picture4Id_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Text4, model.Text4_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Link4, model.Link4_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Picture5Id, model.Picture5Id_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Text5, model.Text5_OverrideForStore, storeScope, false);
_settingService.SaveSettingOverridablePerStore(nivoSliderSettings, x => x.Link5, model.Link5_OverrideForStore, storeScope, false); //now clear settings cache
_settingService.ClearCache(); //get current picture identifiers
var currentPictureIds = new[]
{
nivoSliderSettings.Picture1Id,
nivoSliderSettings.Picture2Id,
nivoSliderSettings.Picture3Id,
nivoSliderSettings.Picture4Id,
nivoSliderSettings.Picture5Id
}; //delete an old picture (if deleted or updated)
foreach (var pictureId in previousPictureIds.Except(currentPictureIds))
{
var previousPicture = _pictureService.GetPictureById(pictureId);
if (previousPicture != null)
_pictureService.DeletePicture(previousPicture);
} SuccessNotification(_localizationService.GetResource("Admin.Plugins.Saved"));
return Configure();
}

提交配置代码

啰嗦了这么多,其实就是一样,在Setting表中插入一条绑定商城Id的记录如下图:

Name就是对应的配置字段,Value为值,StoreId为商城id。

五.总结

1.IPlugin接口,Install(),Uninstall()分别用于安装及卸载

2.IWidgetPlugin接口,GetConfigurationRoute方法用于返回配置接口的路由信息

3.视图中@Html.Action("StoreScopeConfiguration", "Setting", new { area = "Admin" })用于多店配置

4.多店属性设置使用@Html.OverrideStoreCheckboxFor扩展。

5.多店设置保存使用ISettingService接口SaveSettingOverridablePerStore方法。

文中有错误的理解和不正确的观点请指正、留言、一起交流共同进步。

本文地址:http://www.cnblogs.com/yaoshangjin/p/7264414.html

本文为大波浪原创、转载请注明出处。

nopCommerce 3.9 大波浪系列 之 开发支持多店的插件的更多相关文章

  1. nopCommerce 3.9 大波浪系列 之 外部授权登录插件的开发实现

    一.简介 nop支持第三方外部授权登录的扩展,本篇通过编写微信公众平台登录插件进一步了解nop授权登录的开发过程. 微信公众平台.微信开放平台使用场景不一样,前者通过微信客户端进行开发如公众号,后者基 ...

  2. nopCommerce 3.9 大波浪系列 之 引擎 NopEngine

    本章涉及到的内容如下 1.EngineContext初始化IEngine实例 2.Autofac依赖注入初始化 3.AutoMapper框架初始化 4.启动任务初始化 一.EngineContext初 ...

  3. nopCommerce 3.9 大波浪系列 之 网页加载Widgets插件原理

    一.插件简介 插件用于扩展nopCommerce的功能.nopCommerce有几种类型的插件如:支付.税率.配送方式.小部件等(接口如下图),更多插件可以访问nopCommerce官网. 我们看下后 ...

  4. nopCommerce 3.9 大波浪系列 之 global.asax

    一.nop的global.asax文件 nop3.9基于ASP.NET MVC 5框架开发,而ASP.NET MVC中global.asax文件包含全局应用程序事件的事件处理程序,它响应应用程序级别和 ...

  5. nopCommerce 3.9 大波浪系列 之 事件机制(生产者、消费者)

    一.nop事件机制简介 应用场景:客户支付成功后,需要发送短信.邮件告知客户订单支付成功(短信.邮件由不同模块实现) 实现方法: 1.定义支付成功OrderPaidEvent事件. 2.定义短信,邮箱 ...

  6. nopCommerce 3.9 大波浪系列 之 可退款的支付宝插件(下)

    一.回顾 支付宝插件源码下载地址:点击下载 上篇介绍了使用支付宝插件进行支付,全额退款,部分退款还有插件的多店铺配置,本文介绍下如何实现的. 二.前期准备 插件主要有3个功能: 多店铺插件配置 支付功 ...

  7. nopCommerce 3.9 大波浪系列 之 微信公众平台登录插件

    一.简介 插件源码下载:点击下载 微信公众平台网站授权帮助地址:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp142114084 ...

  8. nopCommerce 3.9 大波浪系列 之 使用Redis主从高可用缓存

    一.概述 nop支持Redis作为缓存,Redis出众的性能在企业中得到了广泛的应用.Redis支持主从复制,HA,集群. 一般来说,只有一台Redis是不可行的,原因如下: 单台Redis服务器会发 ...

  9. nopCommerce 3.9 大波浪系列 之 使用部署在Docker中的Redis缓存主从服务

    一.概述 nop支持Redis作为缓存,Redis出众的性能在企业中得到了广泛的应用.Redis支持主从复制,HA,集群. 一般来说,只有一台Redis是不可行的,原因如下: 单台Redis服务器会发 ...

随机推荐

  1. 从netty源码里拿到的关于http错误码,自己学习下

    public static HttpResponseStatus valueOf(int code) { switch (code) { case 100: return CONTINUE; case ...

  2. DOM事件类型总结大全

    unload:事件在用户退出页面时发生 window.onload = function(){ return "页面关闭!"; }; onblur:失去焦点发生变化 window. ...

  3. [0] 服务器 TCP 提供程序无法在 [ 'any' <ipv4> *] 上侦听。TCP 端口已在使用中。

    配置工具——配置管理器——SQLEXPRESS协议下的TCP/IP协议 将其已启用改为禁用. 同时停止SQLEXPRESS服务即可

  4. tcp_wrapper 总结

    一. 简介 tcp_wrapper:tcp包装器, 工作于库中的. 访问控制 工具/组件 : 传输层 和 接近于应用层; 仅对使用tcp协议且在开发时调用了libwrap相关的服务程序有效. 二. 判 ...

  5. linux下安装QT5:error: unrecognized command line option ‘-fuse-ld=gold’

    安装qt时在执行./configure时报错:error: unrecognized command line option '-fuse-ld=gold' 这个错误是qt的一个bug. 在装有gol ...

  6. linux 小技巧(查找替换文件中的ascii编码字符)

    这里纪录一些linux下用到的小技巧,以免遗忘 在linux中经常碰见各种文件处理.最常用的就是替换文件中的某些字符.常见字符替换还是很容易完成.但是有些不可见字符以及ascii编码字符等等都无法直接 ...

  7. [leetcode-605-Can Place Flowers]

    Suppose you have a long flowerbed in which some of the plots are planted and some are not. However, ...

  8. 传输层socket通讯之java实现

    使用流套接字来示例一个客户/服务器的应用.客户端的应用连接到服务器上面,服务端的应用发送数据到客户端,然后客户将收到的数据显示出来. 服务端代码: package socket; import jav ...

  9. 你应该知道的jQuery技巧【收藏】

    jQuery的存在,让学习前端开发的人感到前端越来越容易入门了,用简单的几行代码就可以实现需求,但是,你真的会用jQuery么,当代码运行 后无法看到自己预期的效果,是不是觉得jQuery出了问题,其 ...

  10. panic和recover的使用规则

    转自个人博客 chinazt.cc 在上一节中,我们介绍了defer的使用. 这一节中,我们温习一下panic和recover的使用规则. 在golang当中不存在tye ... catch 异常处理 ...