受欢迎的博客标签

NopCommerce 4.x Admin:How to create admin in NopCommerce 4.x step by step

Published

Bootstrap v4.5.2

path:/src/Presentation/Nop.Web/wwwroot/lib_npm/bootstrap/css/bootstrap.min.css

Quick start

Step 1. Create direcotry name with Areas (新建areas 目录)

Step 2.新建Controller目录

添加控制器HomeController

Step 3.添加路由

Add the following code to the Configure method in your Application's Startup class if not already done:

     

app.UseEndpoints(endpoints =>
        {
          endpoints.MapControllerRoute(
            name : "areas",
            pattern : "{area:exists}/{controller=Home}/{action=Index}/{id?}"
          );
        });
app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");

            endpoints.MapControllerRoute(
            name: "areas",
            pattern: "{area}/{controller}/{did?}/{action=Index}/{id?}");
        });

 

访问

http://localhost:5000/stockso/home

出现下面的错误:

An unhandled exception occurred while processing the request.
InvalidOperationException: The view 'Index' was not found. The following locations were searched:
/Areas/Stockso/Views/Home/Index.cshtml
/Areas/Stockso/Views/Shared/Index.cshtml
/Views/Shared/Index.cshtml
/Pages/Shared/Index.cshtml

添加View目录

 

step 1: create areas  name with Admin

src\ElasticsearchWebSearch\Elasticsearch.Web\Areas\StocksoData\

  <ItemGroup>
    <Folder Include="Areas\Bootstrap5\Data\" />
    <Folder Include="Areas\Bootstrap5\Models\" />
   + <Folder Include="Areas\StocksoData\Controllers\" />
   + <Folder Include="Areas\StocksoData\Data\" />
   + <Folder Include="Areas\StocksoData\Models\" />
   + <Folder Include="Areas\StocksoData\Views\" />
    <Folder Include="Views\Indexer\" />
  </ItemGroup>

step 2:Add Controller

1. Add BaseAdminController

Nop.Web.Areas.Admin.BaseAdminController<-Nop.Web.Framework.Controllers.BaseController<-Controller

add  [Area("Admin")] or [Area(AreaNames.Admin)] on Nop.Web.Areas.Admin.BaseAdminController

2.Add BlogController

\src\Presentation\Nop.Admin\Controllers\BlogController.cs

namespace Nop.Admin.Controllers
{
    public class BlogController :  BaseAdminController
    {

3. Add below code in Nop.Web.Start.cs  


 
In order to not specify any area name, you can use this.

app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");

            endpoints.MapControllerRoute(
            name: "areas",
            pattern: "{area}/{controller}/{did?}/{action=Index}/{id?}");
        });

 

step 3. Add Models

4.Models Validators

Install FluentValidation

<PackageReference Include="FluentValidation" Version="8.5.1" />
    <PackageReference Include="FluentValidation.AspNetCore" Version="8.5.1" />
    <PackageReference Include="FluentValidation.ValidatorAttribute" Version="8.5.1" />

add rule

src\Presentation\Nop.Admin\Validators\Blogs\BlogPostValidator.cs

using FluentValidation;
using Nop.Admin.Models.Blogs;
using Nop.Services.Localization;
using Nop.Web.Framework.Validators;

namespace Nop.Admin.Validators.Blogs
{
    public class BlogPostValidator : BaseNopValidator<BlogPostModel>
    {
        public BlogPostValidator(ILocalizationService localizationService)
        {
            RuleFor(x => x.Title)
                .NotEmpty()
                .WithMessage(localizationService.GetResource("Admin.ContentManagement.Blog.BlogPosts.Fields.Title.Required"));

            RuleFor(x => x.Body)
                .NotEmpty()
                .WithMessage(localizationService.GetResource("Admin.ContentManagement.Blog.BlogPosts.Fields.Body.Required"));

            //blog tags should not contain dots
            //current implementation does not support it because it can be handled as file extension
            RuleFor(x => x.Tags)
                .Must(x => x == null || !x.Contains("."))
                .WithMessage(localizationService.GetResource("Admin.ContentManagement.Blog.BlogPosts.Fields.Tags.NoDots"));

        }
    }
}

 

use

\src\Presentation\Nop.Admin\Models\Blogs\BlogPostModel.cs

using FluentValidation.Attributes;
...

namespace Nop.Admin.Models.Blogs
{
    [Validator(typeof(BlogPostValidator))]
    public partial class BlogPostModel : BaseNopEntityModel
    {
        [NopResourceDisplayName("Admin.ContentManagement.Blog.BlogPosts.Fields.Language")]
        public ObjectId LanguageId { get; set; }

        [NopResourceDisplayName("Admin.ContentManagement.Blog.BlogPosts.Fields.Language")]
        
        public string LanguageName { get; set}
        ...
    }
}

 

 

 

5.AdminAntiForgery

[AdminAntiForgery(true)] 

AdminAntiForgeryAttribute

src\Presentation\Nop.Web.Framework\Security\AdminAntiForgeryAttribute.cs

namespace Nop.Web.Framework.Security
{
    public class AdminAntiForgeryAttribute : TypeFilterAttribute
    {
        /// <summary>
   ..
     }
}

 

use

src\Presentation\Nop.Admin\Controllers\DownloadController.cs

 [HttpPost]
        //do not validate request token (XSRF)
        [AdminAntiForgery(true)] 
        public virtual IActionResult SaveDownloadUrl(string downloadUrl)
        {
            //insert
            var download = new Download
            {
                DownloadGuid = Guid.NewGuid(),
                UseDownloadUrl = true,
                DownloadUrl = downloadUrl,
                IsNew = true
              };
            _downloadService.InsertDownload(download);

            return Json(new { downloadId = download.Id });
        }

 

6.add Models Automapper

src\Presentation\Nop.Admin\Controllers\SettingController.cs

 public ActionResult EmailAccount()
        {
            //if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
            //    return AccessDeniedView();

         

            var emailAccountSettings = _settingService.GetSetting<EmailAccountSettings>();


            var configuration = new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<EmailAccountSettings, EmailAccountSettingsModel>();
               
            });

            var mapper = configuration.CreateMapper();

            var model = mapper.Map<EmailAccountSettingsModel>(emailAccountSettings);

            

            return View(model);
        }

 

  {
            //if (!_permissionService.Authorize(StandardPermissionProvider.ManageSettings))
            //    return AccessDeniedView();

            //load settings for a chosen store scope
            //var storeScope = this.GetActiveStoreScopeConfiguration(_storeService, _workContext);

            if (ModelState.IsValid)
            {
                var emailAccountSettings = _settingService.GetSetting<EmailAccountSettings>();

               
               

                var configuration = new MapperConfiguration(cfg =>
                {
                    cfg.CreateMap<EmailAccountSettingsModel,EmailAccountSettings>();

                });

                var mapper = configuration.CreateMapper();

                emailAccountSettings = mapper.Map<EmailAccountSettings>(model);



                _settingService.SaveSetting<EmailAccountSettings>(emailAccountSettings);
..
}

 

add 菜单

 

sitemap.config:菜单项目定义文件,包含菜单名称、访问路径和访问权限

src\Presentation\Nop.Admin\sitemap.config

<?xml version="1.0" encoding="utf-8" ?>
<siteMap>
  <siteMapNode SystemName="Home" nopResource="Admin.Home" controller="Home" action="Overview">
    <siteMapNode SystemName="Dashboard" nopResource="Admin.Dashboard" controller="Home" action="Index" IconClass="fa-desktop" />
    <siteMapNode SystemName="Catalog" nopResource="Admin.Catalog" PermissionNames="ManageProducts,ManageCategories,ManageManufacturers,ManageProductReviews,ManageProductTags,ManageAttributes" IconClass="fa-book" >
     
    </siteMapNode>

 

添加控制器权限管理

定义权限的静态类

G:\Nopcommerce\wwwstocksocom\src\Libraries\Nop.Services\Security\StandardPermissionProvider.cs

namespace Nop.Services.Security
{
    /// <summary>
    /// Standard permission provider
    /// </summary>
    public partial class StandardPermissionProvider : IPermissionProvider
    {
        //admin area permissions
        public static readonly PermissionRecord AccessAdminPanel = new PermissionRecord { Name = "Access admin area", SystemName = "AccessAdminPanel", Category = "Standard" };
        public static readonly PermissionRecord AllowCustomerImpersonation = new PermissionRecord { Name = "Admin area. Allow Customer Impersonation", SystemName = "AllowCustomerImpersonation", Category = "Customers" };
        ...
     }
}

将用户角色和定义的权限进行比较,若有权限则返回true

 public ActionResult List()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageBlog))
                return AccessDeniedView();

            return View();

        }

startup.cs

step 1: add IWebHostEnvironment

namespace Nop.Admin
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
        {
            Configuration = configuration;
            _webHostEnvironment = webHostEnvironment;
        }

        public IConfiguration Configuration { get; }
        private readonly IWebHostEnvironment _webHostEnvironment;

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)

 

客户端和服务端api交互

kendui 要用到json 返回的变量名第一个字母大写,才显示正常。缺省的模板api是小写。

install Microsoft.AspNetCore.Mvc.NewtonsoftJson Nuget Package

in the Startup’s ConfigureServices, you will need to configure MVC like this:

services.AddControllers()
    .AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.ContractResolver = new DefaultContractResolver();
    });

 

运行后台安装中、english语言包

Language

LocaleStringResource 语言ID要保持一致