nopcommerce中文网

nopcommerce是国外asp.net领域一个高质量的b2c开源项目,基于EntityFramework和MVC开发,QQ群1:75272942(2000人超级群,已满) QQ群2:640322459

导航 - 搜索

nopcommerce之移动版简介

很多朋友在看nopcommerce源码的时候都会忽略里面很重要的一块,那就是nopcommerce移动版,事实上从nopcommerce2.3开始就已经加入了移动版,不过默认是不开启的,你需要在后台综合设置里面启用,启用后可以用iphone、ipad等终端浏览,也可以使用火狐模拟iphone浏览,火狐里面安装插件user agent switcher就可以实现了,因为nopcommerce移动版使用了html5,所有主要是针对触摸屏的终端,效果如图所示:

nopcommere移动版在开发中使用到了html5+mvc+jquery mobile等技术,根据我的了解,这有可能成为未来手机开发的趋势。

1、Jquery mobile构建于Jquery 以及 Jquery UI类库之上,为前端开发人员提供了一个兼容所有主流移动设备平台的统一UI接口系统。拥有出色的弹性,轻量化以及渐进增强特性与可访问性。 更多内容请查看: http://jquerymobile.com/http://www.jqmapi.com/

2、html5作为新一代的html标准,也有其独特的优势。

HTML5 是如何起步的?

HTML5 是 W3C 与 WHATWG 合作的结果。

编者注:W3C 指 World Wide Web Consortium,万维网联盟。

编者注:WHATWG 指 Web Hypertext Application Technology Working Group。

WHATWG 致力于 web 表单和应用程序,而 W3C 专注于 XHTML 2.0。在 2006 年,双方决定进行合作,来创建一个新版本的 HTML。

为 HTML5 建立的一些规则:

  • 新特性应该基于 HTML、CSS、DOM 以及 JavaScript。
  • 减少对外部插件的需求(比如 Flash)
  • 更优秀的错误处理
  • 更多取代脚本的标记
  • HTML5 应该独立于设备
  • 开发进程应对公众透明

新特性

HTML5 中的一些有趣的新特性:

  • 用于绘画的 canvas 元素
  • 用于媒介回放的 video 和 audio 元素
  • 对本地离线存储的更好的支持
  • 新的特殊内容元素,比如 article、footer、header、nav、section
  • 新的表单控件,比如 calendar、date、time、email、url、search

浏览器支持

最新版本的 Safari、Chrome、Firefox 以及 Opera 支持某些 HTML5 特性。Internet Explorer 9 将支持某些 HTML5 特性。

更多内容请查看:http://www.w3school.com.cn/html5

3、MVC实现了展示层和逻辑代码的完美分离,并且生成了很干净的html代码,这对于手机开发来说是很重要的,因为传统的web form方式生成了大量的垃圾代码,有些手机在显示上可能会出现问题。

对手机开发感兴趣的朋友不妨看nopcommerce源码的过程中也关注一下这块内容。

分享是一种美。版权所有,转载请注明出处http://www.nopchina.net/

网银在线插件 For Nopcommerce V2.6

网银在线支付插件,下载后通过后台插件管理安装、配置即可使用。

下载:Nop.Plugin.Payments.Chinabank.zip (43.12 kb)

源代码放在\Plugins目录下,用vs2010打开重新生成。

分享是一种美。版权所有,转载请注明出处 http://www.nopchina.net/

【转】nopcommerce插件深度剖析

nopcommerce插件机制是相当优秀的,所以就分析一下然后拿来所用,集成到自己的网站架构里。写篇小文记录一下。不足和错误之处还望指正,nop版本2.5

1.Nop.Core.Plugins核心文件夹

文件目录:

 

这里面是Plugins的基类文件夹,实现插件机制的核心部分。

IPluginFinder.cs接口:

获取插件的信息接口,在ioc里的Nop.Web.Framework.DependencyRegistrar注册此接口。

系统启动的时候会加载到内存里。

//plugins
builder.RegisterType<PluginFinder>().As<IPluginFinder>().InstancePerHttpRequest();

 IPlugin.cs:

插件的操作接口,主要有设置插件的属性信息,安装插件接口,卸载插件接口。

BasePlugins.cs 实现IPlugin.cs的方法。

PluginDescriptor.cs  插件的实体类,包含了插件的版本、描述,类型,文件名称,作者,等等一系列状态。

PluginFileParser。cs 包含对插件的实体操作方法,主要是写入插件的描述信息。

PluginFinder.cs 加载所有的插件,并获取它们的信息.

PluginManager.cs 插件管理的主类,看里面的注释,它的插件机制应该是参考的Umbraco这个cms的。

2.自定义插件

在这里我演示一个空的插件,本来是写抓取程序的,时间关系,没有做 了。插件名称,Nop.Plugin.Crawler

第一步:新建一个类库项目,而不是mvc应用项目。

第二步:在你的项目里添加需要的文件夹和文件:

Controllers,必选,控制器

Models,可选,如果你的项目很简单的话。

Views,可选但是一般情况下都需要有个界面的,放razor模板的.

Description.txt,这个必须要,插件的版本描述信息。内容如下

Group: Crawler
FriendlyName:Crawler
SystemName: Nop.Plugin.Crawler
Version: 1.00
SupportedVersions: 2.50
Author: nopCommerce team
DisplayOrder: 1
FileName: Nop.Plugin.Crawler.dll

在它上面点右键设置属性,如下图

 

 

Notes.txt ,这个是插件的备注信息,描述了插件的文件位置和一些注意事项。

RouteProvider.cs,路由文件,继承自Nop.Web.Framework.Mvc.Routes.IRouteProvider

View Code
using System.Web.Mvc; using System.Web.Routing; using Nop.Web.Framework.Mvc.Routes; namespace Nop.Plugin.Crawler { public partial class RouteProvider : IRouteProvider { public void RegisterRoutes(RouteCollection routes) { routes.MapRoute("Nop.Plugin.Crawler", "Plugins/Crawler/Index", new { controller = "Crawler", action = "Index" }, new[] { "Nop.Plugin.Crawler.Controllers" } ); } public int Priority { get { return 0; } } } }

web.config,.net配置文件。

CrawlerController.cs 在我的控制器里定义了一个返回简单页面的方法。

using System.Web.Mvc; using Nop.Web.Framework.Controllers; namespace Nop.Plugin.Crawler.Controllers { [AdminAuthorize] public class CrawlerController : Controller { public ActionResult Index() { return View("Nop.Plugin.Crawler.Views.Index"); } } }

大家注意了,返回的View里的view路径是插件里的视图路径,在view的Index.cshtml点右键设置的属性,cshtml是编译到dll里的

还有整个插件的属性,在插件项目上点右键设置输出属性

最后设置引用进来的dll文件属性。这样输出dll文件的时候不会把其他乱七八糟的文件也拷贝过来了。

在插件上点右键生只输出这三个文件 

3.最后一步在Nop.Web的InstalledPlugins.txt里添加插件

插件名称不能重复,可以自定义。这里我的取的名字和插件项目名称相同没什么特殊要求。

 

 后台插件预览就可以看到了。

 

教你一招 - 如何给nopcommerce增加新闻类别模块

nopcommerce的新闻模块一直都没有新闻类别,但是很多情况下都会使用到类别,怎么办呢,自己动手吧。

1、首先创建新闻类别表,脚本如下:

CREATE TABLE [dbo].[NewsCategory](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[Name] [nvarchar](400) NOT NULL,
	[Description] [nvarchar](max) NOT NULL,
	[ParentCategoryId] [int] NOT NULL,
	[Published] [bit] NOT NULL,
	[Deleted] [bit] NOT NULL,
	[DisplayOrder] [int] NOT NULL,
	[CreatedOn] [datetime] NOT NULL,
	[UpdatedOn] [datetime] NOT NULL,
 CONSTRAINT [PK_NewsCategory] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO



2、\Libraries\Nop.Core\Domain\News下面增加实体类,代码如下:

using System;
using System.Collections.Generic;
using Nop.Core.Domain.Localization;

namespace Nop.Core.Domain.News
{
    /// <summary>
    /// Represents a news category
    /// </summary>
    public partial class NewsCategory : BaseEntity
    {
        /// <summary>
        /// Gets or sets the name
        /// </summary>
        public virtual string Name { get; set; }

        /// <summary>
        /// Gets or sets the description
        /// </summary>
        public virtual string Description { get; set; }

        /// <summary>
        /// Gets or sets the parent category identifier
        /// </summary>
        public virtual int ParentCategoryId { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the entity is published
        /// </summary>
        public virtual bool Published { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the entity has been deleted
        /// </summary>
        public virtual bool Deleted { get; set; }

        /// <summary>
        /// Gets or sets the display order
        /// </summary>
        public virtual int DisplayOrder { get; set; }

        /// <summary>
        /// Gets or sets the date and time of instance creation
        /// </summary>
        public virtual DateTime CreatedOn { get; set; }

        /// <summary>
        /// Gets or sets the date and time of instance update
        /// </summary>
        public virtual DateTime UpdatedOn { get; set; }
    }
}



3、\Libraries\Nop.Data\Mapping\News下面增加新闻类别映射类,因为nopcommerce使用Entity Framework (EF) Code-First方法,
允许你在nopcommerce代码中定义实体 (所有的核心实体类都在Nop.Core中定义),所以必须在此添加映射类,代码如下:

using System.Data.Entity.ModelConfiguration;
using Nop.Core.Domain.News;

namespace Nop.Data.Mapping.News
{
    public partial class NewsCategoryMap : EntityTypeConfiguration<NewsCategory>
    {
        public NewsCategoryMap()
        {
            this.ToTable("NewsCategory");
            this.HasKey(bp => bp.Id);
            this.Property(bp => bp.Name).IsRequired().IsMaxLength();
            this.Property(bp => bp.Description).IsRequired().IsMaxLength();
        }
    }
}



4、\Libraries\Nop.Services\News下面的INewsService.cs和NewsService.cs增加新闻类别相关操作。
INewsService.cs整理后代码如下:

using System;
using System.Collections.Generic;
using Nop.Core;
using Nop.Core.Domain.News;

namespace Nop.Services.News
{
    /// <summary>
    /// News service interface
    /// </summary>
    public partial interface INewsService
    {
        #region news

        /// <summary>
        /// Deletes a news
        /// </summary>
        /// <param name="newsItem">News item</param>
        void DeleteNews(NewsItem newsItem);

        /// <summary>
        /// Gets a news
        /// </summary>
        /// <param name="newsId">The news identifier</param>
        /// <returns>News</returns>
        NewsItem GetNewsById(int newsId);

        /// <summary>
        /// Gets all news
        /// </summary>
        /// <param name="languageId">Language identifier; 0 if you want to get all records</param>
        /// <param name="dateFrom">Filter by created date; null if you want to get all records</param>
        /// <param name="dateTo">Filter by created date; null if you want to get all records</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>News items</returns>
        IPagedList<NewsItem> GetAllNews(int languageId,
            DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false);

        /// <summary>
        /// Inserts a news item
        /// </summary>
        /// <param name="news">News item</param>
        void InsertNews(NewsItem news);

        /// <summary>
        /// Updates the news item
        /// </summary>
        /// <param name="news">News item</param>
        void UpdateNews(NewsItem news);
        #endregion

        #region news category

        /// <summary>
        /// Deletes a news category
        /// </summary>
        /// <param name="category">News Category item</param>
        void DeleteNewsCategory(NewsCategory category);

        /// <summary>
        /// Gets a news category
        /// </summary>
        /// <param name="categoryId">The news category identifier</param>
        /// <returns>NewsCategory</returns>
        NewsCategory GetNewsCategoryById(int categoryId);

        /// <summary>
        /// Gets all news category
        /// </summary>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>News Category items</returns>
        IPagedList<NewsCategory> GetAllNewsCategory(int pageIndex, int pageSize, bool showHidden = false);

        /// <summary>
        /// Gets all news category
        /// </summary>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>News Category items</returns>
        IList<NewsCategory> GetAllNewsCategory(bool showHidden = false);

        /// <summary>
        /// Inserts a news category item
        /// </summary>
        /// <param name="category">News Category item</param>
        void InsertNewsCategory(NewsCategory category);

        /// <summary>
        /// Updates the news category item
        /// </summary>
        /// <param name="category">News Category item</param>
        void UpdateNewsCategory(NewsCategory category);

        #endregion
    }
}


NewsService.cs整理后代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using Nop.Core;
using Nop.Core.Caching;
using Nop.Core.Data;
using Nop.Core.Domain.News;
using Nop.Core.Events;

namespace Nop.Services.News
{
    /// <summary>
    /// News service
    /// </summary>
    public partial class NewsService : INewsService
    {
        #region Constants
        private const string NEWS_BY_ID_KEY = "Nop.news.id-{0}";
        private const string NEWS_PATTERN_KEY = "Nop.news.";
        private const string NEWSCATEGORY_BY_ID_KEY = "Nop.newscategory.id-{0}";
        private const string NEWSCATEGORY_PATTERN_KEY = "Nop.newscategory.";
        #endregion

        #region Fields

        private readonly IRepository<NewsItem> _newsItemRepository;
        private readonly IRepository<NewsCategory> _newsCategoryRepository;
        private readonly ICacheManager _cacheManager;
        private readonly IEventPublisher _eventPublisher;

        #endregion

        #region Ctor

        public NewsService(IRepository<NewsItem> newsItemRepository, IRepository<NewsCategory> newsCategoryRepository, ICacheManager cacheManager, IEventPublisher eventPublisher)
        {
            _newsItemRepository = newsItemRepository;
            _newsCategoryRepository = newsCategoryRepository;
            _cacheManager = cacheManager;
            _eventPublisher = eventPublisher;
        }

        #endregion

        #region Methods

        #region news
        
        /// <summary>
        /// Deletes a news
        /// </summary>
        /// <param name="newsItem">News item</param>
        public virtual void DeleteNews(NewsItem newsItem)
        {
            if (newsItem == null)
                throw new ArgumentNullException("newsItem");

            _newsItemRepository.Delete(newsItem);

            _cacheManager.RemoveByPattern(NEWS_PATTERN_KEY);

            //event notification
            _eventPublisher.EntityDeleted(newsItem);
        }

        /// <summary>
        /// Gets a news
        /// </summary>
        /// <param name="newsId">The news identifier</param>
        /// <returns>News</returns>
        public virtual NewsItem GetNewsById(int newsId)
        {
            if (newsId == 0)
                return null;

            string key = string.Format(NEWS_BY_ID_KEY, newsId);
            return _cacheManager.Get(key, () =>
            {
                var n = _newsItemRepository.GetById(newsId);
                return n;
            });
        }

        /// <summary>
        /// Gets all news
        /// </summary>
        /// <param name="languageId">Language identifier; 0 if you want to get all records</param>
        /// <param name="dateFrom">Filter by created date; null if you want to get all records</param>
        /// <param name="dateTo">Filter by created date; null if you want to get all records</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>News items</returns>
        public virtual IPagedList<NewsItem> GetAllNews(int languageId,
            DateTime? dateFrom, DateTime? dateTo, int pageIndex, int pageSize, bool showHidden = false)
        {
            var query = _newsItemRepository.Table;
            if (dateFrom.HasValue)
                query = query.Where(n => dateFrom.Value <= n.CreatedOnUtc);
            if (dateTo.HasValue)
                query = query.Where(n => dateTo.Value >= n.CreatedOnUtc);
            if (languageId > 0)
                query = query.Where(n => languageId == n.LanguageId);
            if (!showHidden)
                query = query.Where(n => n.Published);
            query = query.OrderByDescending(b => b.CreatedOnUtc);

            var news = new PagedList<NewsItem>(query, pageIndex, pageSize);
            return news;
        }
        /// <summary>
        /// Inserts a news item
        /// </summary>
        /// <param name="news">News item</param>
        public virtual void InsertNews(NewsItem news)
        {
            if (news == null)
                throw new ArgumentNullException("news");

            _newsItemRepository.Insert(news);

            _cacheManager.RemoveByPattern(NEWS_PATTERN_KEY);

            //event notification
            _eventPublisher.EntityInserted(news);
        }

        /// <summary>
        /// Updates the news item
        /// </summary>
        /// <param name="news">News item</param>
        public virtual void UpdateNews(NewsItem news)
        {
            if (news == null)
                throw new ArgumentNullException("news");

            _newsItemRepository.Update(news);

            _cacheManager.RemoveByPattern(NEWS_PATTERN_KEY);

            //event notification
            _eventPublisher.EntityUpdated(news);
        }

        #endregion

        #region news category

        /// <summary>
        /// Deletes a news category
        /// </summary>
        /// <param name="category">News Category item</param>
        public virtual void DeleteNewsCategory(NewsCategory category)
        {
            if (category == null)
                throw new ArgumentNullException("category");

            _newsCategoryRepository.Delete(category);

            _cacheManager.RemoveByPattern(NEWSCATEGORY_PATTERN_KEY);

            //event notification
            _eventPublisher.EntityDeleted(category);
        }

        /// <summary>
        /// Gets a news category
        /// </summary>
        /// <param name="categoryId">The news category identifier</param>
        /// <returns>NewsCategory</returns>
        public virtual NewsCategory GetNewsCategoryById(int categoryId)
        {
            if (categoryId == 0)
                return null;

            string key = string.Format(NEWSCATEGORY_BY_ID_KEY, categoryId);
            return _cacheManager.Get(key, () =>
            {
                var n = _newsCategoryRepository.GetById(categoryId);
                return n;
            });
        }

        /// <summary>
        /// Gets all news category
        /// </summary>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>News Category items</returns>
        public virtual IPagedList<NewsCategory> GetAllNewsCategory(int pageIndex, int pageSize, bool showHidden = false)
        {
            var categories = GetAllNewsCategory(showHidden);
            return new PagedList<NewsCategory>(categories, pageIndex, pageSize);
        }

        /// <summary>
        /// Gets all news category
        /// </summary>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <returns>News Category items</returns>
        public virtual IList<NewsCategory> GetAllNewsCategory(bool showHidden = false)
        {
            var query = _newsCategoryRepository.Table;
            if (!showHidden)
                query = query.Where(n => n.Published);
            query = query.OrderBy(b => b.DisplayOrder);

            var unsortedCategories = query.ToList();

            //sort categories
            var sortedCategories = unsortedCategories.SortCategoriesForTree(0);
            return sortedCategories;
        }

        /// <summary>
        /// Inserts a news category item
        /// </summary>
        /// <param name="category">News Category item</param>
        public virtual void InsertNewsCategory(NewsCategory category)
        {
            if (category == null)
                throw new ArgumentNullException("category");

            _newsCategoryRepository.Insert(category);

            _cacheManager.RemoveByPattern(NEWSCATEGORY_PATTERN_KEY);

            //event notification
            _eventPublisher.EntityInserted(category);
        }

        /// <summary>
        /// Updates the news category item
        /// </summary>
        /// <param name="category">News Category item</param>
        public virtual void UpdateNewsCategory(NewsCategory category)
        {
            if (category == null)
                throw new ArgumentNullException("category");

            _newsCategoryRepository.Update(category);

            _cacheManager.RemoveByPattern(NEWSCATEGORY_PATTERN_KEY);

            //event notification
            _eventPublisher.EntityUpdated(category);
        }

        #endregion

        #endregion
    }
}



另外需要增加NewsExtensions.cs,主要用于新闻类别的排序(对无限极分类的排序等等),代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using Nop.Core.Domain.News;

namespace Nop.Services.News
{
    /// <summary>
    /// Extensions
    /// </summary>
    public static class NewsExtensions
    {
        /// <summary>
        /// Sort news categories for tree representation
        /// </summary>
        /// <param name="source">Source</param>
        /// <param name="parentId">Parent category identifier</param>
        /// <returns>Sorted categories</returns>
        public static IList<NewsCategory> SortCategoriesForTree(this IList<NewsCategory> source, int parentId)
        {
            var result = new List<NewsCategory>();

            var temp = source.ToList().FindAll(c => c.ParentCategoryId == parentId);
            foreach (var cat in temp)
            {
                result.Add(cat);
                result.AddRange(SortCategoriesForTree(source, cat.Id));
            }
            return result;
        }

        public static string GetCategoryNameWithPrefix(this NewsCategory category, INewsService newsService)
        {
            string result = string.Empty;

            while (category != null)
            {
                if (String.IsNullOrEmpty(result))
                    result = category.Name;
                else
                    result = "--" + result;
                category = newsService.GetNewsCategoryById(category.ParentCategoryId);
            }
            return result;
        }

        public static string GetCategoryBreadCrumb(this NewsCategory category, INewsService newsService)
        {
            string result = string.Empty;

            while (category != null && !category.Deleted)
            {
                if (String.IsNullOrEmpty(result))
                    result = category.Name;
                else
                    result = category.Name + " >> " + result;

                category = newsService.GetNewsCategoryById(category.ParentCategoryId);

            }
            return result;
        }

    }
}



5、到此底层的数据操作已经基本完成,开始修改后台管理部分。
Nop.Admin\Models\News\增加新闻类别页面所需要的ViewModel,代码如下:

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using FluentValidation.Attributes;
using Nop.Admin.Validators.News;
using Nop.Web.Framework;
using Nop.Web.Framework.Mvc;

namespace Nop.Admin.Models.News
{
    [Validator(typeof(NewsCategoryValidator))]
    public class NewsCategoryModel : BaseNopEntityModel
    {
        public NewsCategoryModel()
        {
            AvailableCategories = new List<SelectListItem>();
        }

        [NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.Name")]
        public string Name { get; set; }

        [NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.Description")]
        [AllowHtml]
        public string Description { get; set; }

        [NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.ParentName")]
        public int ParentCategoryId { get; set; }

        [NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.ParentName")]
        public string ParentCategoryName { get; set; }

        [NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.Published")]
        public bool Published { get; set; }

        [NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.DisplayOrder")]
        public int DisplayOrder { get; set; }

        [NopResourceDisplayName("Admin.ContentManagement.News.NewsCategoryItems.Fields.CreatedOn")]
        public DateTime CreatedOn { get; set; }

        public IList<SelectListItem> AvailableCategories { get; set; }
    }
}



Nop.Admin\Validators\News\增加类别的验证类NewsCategoryValidator.cs,主要用于后台添加时候的非空字数限制等等,代码如下

using FluentValidation;
using Nop.Admin.Models.News;
using Nop.Services.Localization;

namespace Nop.Admin.Validators.News
{
    public class NewsCategoryValidator : AbstractValidator<NewsCategoryModel>
    {
        public NewsCategoryValidator(ILocalizationService localizationService)
        {
            RuleFor(x => x.Name)
                .NotNull()
                .WithMessage(localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Fields.Name.Required"));

            RuleFor(x => x.Description)
                .NotNull()
                .WithMessage(localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Fields.Description.Required"));
        }
    }
}



修改Nop.Admin/MappingExtensions.cs文件,增加新闻类别相关内容,这几个方法主要是NewsCategoryNewsCategoryModel之间的相互转换,代码如下:

//news category items
        public static NewsCategoryModel ToModel(this NewsCategory entity)
        {
            return Mapper.Map<NewsCategory, NewsCategoryModel>(entity);
        }

        public static NewsCategory ToEntity(this NewsCategoryModel model)
        {
            return Mapper.Map<NewsCategoryModel, NewsCategory>(model);
        }

        public static NewsCategory ToEntity(this NewsCategoryModel model, NewsCategory destination)
        {
            return Mapper.Map(model, destination);
        }



修改Nop.Admin/Infrastructure/AutoMapperStartupTask.cs文件,增加相关映射规则,如果不加的话会出错的哦,
AutoMapper是基于对象到对象约定的映射工具,常用于(但并不仅限制于)把复杂的对象模型转为DTO,一般用于ViewModel模式和跨服务范畴。
AutoMapper给用户提供了便捷的配置API,就像使用约定来完成自动映射那样。
代码如下:

Mapper.CreateMap<NewsCategory, NewsCategoryModel>()
                .ForMember(dest => dest.AvailableCategories, mo => mo.Ignore())
                .ForMember(dest => dest.ParentCategoryName, mo => mo.Ignore())
                .ForMember(dest => dest.CreatedOn, mo => mo.Ignore());
            Mapper.CreateMap<NewsCategoryModel, NewsCategory>()
                .ForMember(dest => dest.CreatedOn, mo => mo.Ignore());

最后修改Nop.Admin\Controllers\NewsController.cs,增加新闻类别的增删改查操作,如下:

#region News category items
        public ActionResult CategoryList()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
                return AccessDeniedView();

            var news = _newsService.GetAllNewsCategory(0, _adminAreaSettings.GridPageSize, true);
            var gridModel = new GridModel<NewsCategoryModel>
            {
                Data = news.Select(x =>
                {
                    var m = x.ToModel();
                    m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOn, DateTimeKind.Utc);
                    m.Name = x.GetCategoryBreadCrumb(_newsService);
                    m.Published = x.Published;
                    m.DisplayOrder = x.DisplayOrder;
                    return m;
                }),
                Total = news.TotalCount
            };
            return View(gridModel);
        }

        [HttpPost, GridAction(EnableCustomBinding = true)]
        public ActionResult CategoryList(GridCommand command)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
                return AccessDeniedView();

            var news = _newsService.GetAllNewsCategory(0, _adminAreaSettings.GridPageSize, true);
            var gridModel = new GridModel<NewsCategoryModel>
            {
                Data = news.Select(x =>
                {
                    var m = x.ToModel();
                    m.CreatedOn = _dateTimeHelper.ConvertToUserTime(x.CreatedOn, DateTimeKind.Utc);
                    m.Name = x.GetCategoryBreadCrumb(_newsService);
                    m.Published = x.Published;
                    m.DisplayOrder = x.DisplayOrder;
                    return m;
                }),
                Total = news.TotalCount
            };
            return new JsonResult
            {
                Data = gridModel
            };
        }

        public ActionResult CategoryCreate()
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
                return AccessDeniedView();

            var model = new NewsCategoryModel();
            //default values
            model.Published = true;

            //categories
            model.AvailableCategories.Add(new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" });
            foreach (var c in _newsService.GetAllNewsCategory(true))
                model.AvailableCategories.Add(new SelectListItem() { Text = c.GetCategoryNameWithPrefix(_newsService), Value = c.Id.ToString() });

            return View(model);
        }
        [HttpPost, FormValueExists("save", "save-continue", "continueEditing")]
        public ActionResult CategoryCreate(NewsCategoryModel model, bool continueEditing)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
                return AccessDeniedView();

            if (ModelState.IsValid)
            {
                var newsItem = model.ToEntity();
                newsItem.CreatedOn = DateTime.UtcNow;
                newsItem.UpdatedOn = DateTime.UtcNow;
                _newsService.InsertNewsCategory(newsItem);

                SuccessNotification(_localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Added"));
                return continueEditing ? RedirectToAction("CategoryEdit", new { id = newsItem.Id }) : RedirectToAction("CategoryList");
            }

            return View(model);
        }

        public ActionResult CategoryEdit(int id)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
                return AccessDeniedView();

            var newsItem = _newsService.GetNewsCategoryById(id);
            if (newsItem == null)
                //No news item found with the specified id
                return RedirectToAction("CategoryList");

            var model = newsItem.ToModel();
            //categories
            model.AvailableCategories.Add(new SelectListItem() { Text = _localizationService.GetResource("Admin.Common.All"), Value = "0" });
            foreach (var c in _newsService.GetAllNewsCategory(true))
                model.AvailableCategories.Add(new SelectListItem() { Text = c.GetCategoryNameWithPrefix(_newsService), Value = c.Id.ToString() });

            return View(model);
        }

        [HttpPost, FormValueExists("save", "save-continue", "continueEditing")]
        public ActionResult CategoryEdit(NewsCategoryModel model, bool continueEditing)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
                return AccessDeniedView();

            var newsItem = _newsService.GetNewsCategoryById(model.Id);
            if (newsItem == null)
                //No news item found with the specified id
                return RedirectToAction("CategoryList");

            if (ModelState.IsValid)
            {
                newsItem = model.ToEntity(newsItem);
                newsItem.UpdatedOn = DateTime.UtcNow;
                _newsService.UpdateNewsCategory(newsItem);

                SuccessNotification(_localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Updated"));
                return continueEditing ? RedirectToAction("CategoryEdit", new { id = newsItem.Id }) : RedirectToAction("List");
            }

            return View(model);
        }

        [HttpPost, ActionName("DeleteCategory")]
        public ActionResult DeleteCategoryConfirmed(int id)
        {
            if (!_permissionService.Authorize(StandardPermissionProvider.ManageNews))
                return AccessDeniedView();

            var newsItem = _newsService.GetNewsCategoryById(id);
            if (newsItem == null)
                //No news item found with the specified id
                return RedirectToAction("CategoryList");

            _newsService.DeleteNewsCategory(newsItem);

            SuccessNotification(_localizationService.GetResource("Admin.ContentManagement.News.NewsCategoryItems.Deleted"));
            return RedirectToAction("CategoryList");
        }

        #endregion


6、接下来就是页面View了,代码太多,这里不再具体列出,不熟悉MVC机制的可以先补充一下MVC相关知识。
稍后整理提供下载。

分享是一种美。版权所有,转载请注明出处 http://www.nopchina.net/

教你一招 - 如何安装nopcommerce2.5

1、确认服务器安装有iis、.net framework4、mvc3、sql server。

2、下载官方no source版压缩包,如果是学习的话也可以下载with source code版。 下载地址

nopchina - 教你一招系列

3、把下载的压缩包解压到指定目录,在iis里面配置好,注意asp.net版本选择和MVC的设置。

4、配置好以后,尝试打开http://xxx/install 第一次打开会进入安装向导页面,创建数据库、管理员、模拟数据等等,如图所示:

nopchina - 教你一招系列

5、按照上图提示输入完整后,点击Install按钮,如果一切正常的话便开始安装,安装成功后就自动跳转到首页。

注:第一次接触mvc版可能不知道链接字符串在哪修改?  在这个文件找找看:\Presentation\Nop.Web\App_Data\Settings.txt。

分享是一种美。版权所有,转载请注明出处 http://www.nopchina.net/