mvc3的实际应用时间还是不长,有些东西正在摸索当中,项目是多用户多模版店铺,以下为实际开发过程中的解决办法,感觉解决方案不是最好的,但是目前只能想到这些,希望园里的大牛们给点建议。

1.项目解决方案的目录结构。

Syw.Core主要放实体类及依赖注入的程序及插件和数据访问接口。

Syw.Data.SqlServer完全是一大堆sql,实现Syw.Core里的IData类。对orm我没深入使用过,还是觉得最大程度的控制我的sql比较放心,所有的集合都是List或者Ilist类型的。

Syw.Services业务处理层,类似以前的bll,这里用的是静态方法,没有走接口了,项目不是特别大,一个人开发,接口太多会很累。

Syw.Test单元测试用的,有时候调试返回结果还是很有用的。

Syw.Admin,后台管理,但是这个我参考的nopcommerce,生成的时候直接在网站更目录下生成Administrator文件夹,View和Content文件夹都在这里,但是dll文件是生成到Syw.Web这个主目录下的,这样我就不需要用二级域名来访问后台了,直接通过http://xxxx.com/admin就可以了。

Syw.Framework主要是一些基础帮助类。例如图片处理,邮件发送帮助类,字符串处理,自定义ui等等。

2.模板路径及结构

a1,a2,b1为不同风格的模板,不仅仅颜色不相同,排版方式也不相同。现在只有三个模板,通过这种方式选择模板。a1,a2为店铺类的,a3为服务类企业用的。

_LayoutStore.cshtml是店铺的主模板页。通过@Hmtl.Action来访问ChildAction加载页面,@RenderBody() 加载主页面。

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<title>@ViewBag.Title -ooxx网</title>
<meta name="keywords" content="@ViewBag.Title">
<meta name="description" content="@ViewBag.Title">
<script type="text/javascript" src="/Scripts/jquery-1.4.4.min.js"></script>
<link href="/StoreThemes/a2/Content/style2.css" type="text/css" rel="stylesheet" />
</head>

<body>
<!--banner以上的头部-->
 @Html.Action("Header", "Store", new { store = ViewBag.Model.Store })
 <!--banner以上的头部 结束-->


     <!--顶部banner和导航--><!--考虑传参数model-->
        @Html.Action("TopBanner", "Store", new { store = ViewBag.Model.Store, act = Url.RequestContext.RouteData.Values["action"].ToString().ToLower() })
        <!--顶部banner和导航结束-->
  <div class="con">

    @Html.Action("SideBar", "Store", new { store = ViewBag.Model.Store })
    <div class="con-right">
        <!-- include -->
        @RenderBody()
        <!-- include end -->
    </div>
  </div>
  
<!-- 页脚 -->
@Html.Action("Footer","Store",new { store = ViewBag.Model.Store })
<!-- 页脚 结束 -->
</body>
</html>

 

StoreController里的关于我们的Action

        #region 关于我们
        /// <summary>
        /// 店铺简介
        /// </summary>
        /// <returns></returns>
        public ActionResult About(int id)
        {
            var model = new StoreModel();
            model.Store = StoreService.GetStoreById(id);
            model.CurrentAction = RouteData.Values["action"].ToString().ToLower().ToLower();
            ViewBag.Model = model;
            return View(model.Store.Theme.ViewPath + "About.cshtml", model);
        }
        #endregion

 

ChildAction如下,网站底部

        [ChildActionOnly]
        public ActionResult Footer(StoreInfo store)
        {
            var model =new StoreModel();
            model.Store = store;
            if (store.Theme != null)
            {
                return PartialView(store.Theme.ViewPath + "Footer.cshtml", model);
            }
            else
            {
                return PartialView(StoreService.GetStoreConfig().DefaultView + "Footer.cshtml", model);
            }
        }

 

后台选择模板

通过这种简单的方式实现了多用户店铺多模板的选择功能,自定义二级域名不在这里赘述了。

自我感觉还有很多不完善的地方,欢迎拍砖。

独立博客地址:http://www.jqpress.com/post/182.aspx

 

posted @ 2012-06-02 16:35 叶鹏 阅读(674) 评论(3) 编辑

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里添加插件

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

 

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

 原文来自:http://www.jqpress.com/post/178.aspx

 独立博客:http://www.jqpress.com

posted @ 2012-05-31 16:18 叶鹏 阅读(682) 评论(4) 编辑

偶尔翻到豆瓣里一篇对中国屌丝的批评,突然想到当年美国那个垮掉的一代,吸毒,淫乱,绝望的生存,而如今我们苦逼的80后自诩为屌丝的时候,也不想想每一个堕落的时代还是有牛逼的人存在,中国的大学,绝大部分在逃课,生殖冲动,暗无天日的游戏,苦逼学习的几乎是不入群,悲观消极的情绪像哈欠一样传染着每一个容易被感染的苦逼青年。毕业后即失业,人生没有方向,更无从理想了,傻逼的政府不知道怎么搞教育,造就了一群乌合之众的国家,纵使在这样的环境下,还是有人为理想奋斗着,每一天在充实,相信总有一天会有自己出头的。

我不吸毒,不喝酒,不打游戏,不搞乌烟瘴气的社会关系,在苦逼的it路上挨踢,虽然天资和能力都进不了微软google之类的公司,每天在自己既定的方向一步步前进。做着自己喜欢做的事情,认真做好每一件事情。摆脱虚伪的自我,既敢为了感情牺牲失业,又要做到掌握自己人生的方向,拒绝屌丝的自嘲,拒绝屌丝的人生。

当明白一切时,秋叶已泛黄,在收获的季节里播种,是期望下一个春天还是奢望冬天来临时那无几的颗实,纵使如此,朝闻道夕可死。

原文出处:http://www.jqpress.com/post/165.aspx

独立博客:http://www.jqpress.com

posted @ 2012-05-06 16:40 叶鹏 阅读(36) 评论(0) 编辑

第一个代码文件

View Code
 public class DomainRoute : Route
{
private Regex domainRegex;
private Regex pathRegex;

public string Domain { get; set; }

public DomainRoute(string domain, string url, RouteValueDictionary defaults)
: base(url, defaults, new MvcRouteHandler())
{
Domain = domain;
}

public DomainRoute(string domain, string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
: base(url, defaults, routeHandler)
{
Domain = domain;
}

public DomainRoute(string domain, string url, object defaults)
: base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
{
Domain = domain;
}

public DomainRoute(string domain, string url, object defaults, IRouteHandler routeHandler)
: base(url, new RouteValueDictionary(defaults), routeHandler)
{
Domain = domain;
}

public override RouteData GetRouteData(HttpContextBase httpContext)
{
// 构造 regex
domainRegex = CreateRegex(Domain);
pathRegex = CreateRegex(Url);

// 请求信息
string requestDomain = httpContext.Request.Headers["host"];
if (!string.IsNullOrEmpty(requestDomain))
{
if (requestDomain.IndexOf(":") > 0)
{
requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":"));
}
}
else
{
requestDomain = httpContext.Request.Url.Host;
}
string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

// 匹配域名和路由
Match domainMatch = domainRegex.Match(requestDomain);
Match pathMatch = pathRegex.Match(requestPath);

// 路由数据
RouteData data = null;
if (domainMatch.Success && pathMatch.Success)
{
data = new RouteData(this, RouteHandler);

// 添加默认选项
if (Defaults != null)
{
foreach (KeyValuePair<string, object> item in Defaults)
{
data.Values[item.Key] = item.Value;
}
}

// 匹配域名路由
for (int i = 1; i < domainMatch.Groups.Count; i++)
{
Group group = domainMatch.Groups[i];
if (group.Success)
{
string key = domainRegex.GroupNameFromNumber(i);

if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
{
if (!string.IsNullOrEmpty(group.Value))
{
data.Values[key] = group.Value;
}
}
}
}

// 匹配域名路径
for (int i = 1; i < pathMatch.Groups.Count; i++)
{
Group group = pathMatch.Groups[i];
if (group.Success)
{
string key = pathRegex.GroupNameFromNumber(i);

if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
{
if (!string.IsNullOrEmpty(group.Value))
{
data.Values[key] = group.Value;
}
}
}
}
}

return data;
}

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return base.GetVirtualPath(requestContext, RemoveDomainTokens(values));
}

public DomainData GetDomainData(RequestContext requestContext, RouteValueDictionary values)
{
// 获得主机名
string hostname = Domain;
foreach (KeyValuePair<string, object> pair in values)
{
hostname = hostname.Replace("{" + pair.Key + "}", pair.Value.ToString());
}

// Return 域名数据
return new DomainData
{
Protocol = "http",
HostName = hostname,
Fragment = ""
};
}

private Regex CreateRegex(string source)
{
// 替换
source = source.Replace("/", @"\/?");
source = source.Replace(".", @"\.?");
source = source.Replace("-", @"\-?");
source = source.Replace("{", @"(?<");
source = source.Replace("}", @">([a-zA-Z0-9_]*))");

return new Regex("^" + source + "$");
}

private RouteValueDictionary RemoveDomainTokens(RouteValueDictionary values)
{
Regex tokenRegex = new Regex(@"({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?");
Match tokenMatch = tokenRegex.Match(Domain);
for (int i = 0; i < tokenMatch.Groups.Count; i++)
{
Group group = tokenMatch.Groups[i];
if (group.Success)
{
string key = group.Value.Replace("{", "").Replace("}", "");
if (values.ContainsKey(key))
values.Remove(key);
}
}

return values;
}
}

第二个代码文件

    public class DomainData
{
public string Protocol { get; set; }
public string HostName { get; set; }
public string Fragment { get; set; }
}

在global里注册实现

            routes.Add("DomainRoute", new DomainRoute(
"{subdomain}.您的域名.com", // Domain with parameters
"{controller}/{action}/{id}", // URL with parameters
new { subdomain = "", controller = "Home", action = "Index", id = "" } // Parameter defaults
));


在HomeController的index 里获取域名值

            //获取二级域名
var subdomain = RouteData.Values["subdomain"].ToString();

剩下的工作接着做



posted @ 2012-02-29 13:41 叶鹏 阅读(511) 评论(12) 编辑

       建议博客园成立中国的开源项目组织,园子里这么多大牛,更多技术爱好者和分享者,而且很多牛人也有自己的开源项目托管在googlecode,codeplex,sourceforge,github,或者自己的爱机里,如果博客园里能专门托管园子里大牛的开源项目不是更好吗,每年选取一两个优秀的项目应该就够了(在这里更正一下,不是源码托管站,是类似apache的孵化器组织)况且园子里也有很多优秀的专题小组,资源要利用啊。如果有技术类商业公司赞助博客园的开源项目,既宣传了企业又推动了博客园发展,大家各取所需不也是很好吗?

 

      当然让dudu做这个决定是艰难的,服务器要钱,人员要钱,所以要园友们共同支持,能孵化出中国自己的商业开源项目,哪怕是梦也要梦一下。作为长年泡在园子里的园友更希望博客园成为中国最好的技术社区,比那些广告满天飞的所谓的中国最大的技术社区更有影响力,事情是一件一件做出来的,估计dudu从来也没闲着,但是提出这个意见还是希望dudu做一个艰难的决定。

 

      做一件事情开始一定是艰难的,下面的批评都有道理,博客园不就是这样坚持下来的吗。但是相信dudu,也相信园友,很小的项目哪怕是个小blog,小cms,小工具,一粒种子很可能就会成为大树。况且中国暂时没发现有有影响力的开源组织,有不少个人开源项目站点和大量的垃圾源码站。

 

      好吧,那还是让园友做这个艰难的决定了,同意的推荐一下,不同意的反对一下。

      ps一下:有个人的开源或者准备开源的项目爆出来给dudu和园友看看

posted @ 2011-11-16 16:19 叶鹏 阅读(5494) 评论(183) 编辑
摘要: 昨天和别人讨论了一下linq的性能,自我觉得linq的性能不行,但是实际上linq还是在性能上有过人之处的,linq to sql除外,以下是简单的性能测试比较代码,在这里解释一下,代码的执行速度计时测试不能用datetime了,我还是个小白,刚开始用的datetime,结果发现linq的性能并不行,但是用StopWatch才发现了事实,以前对linq的偏见的同学还是拥抱一下linq吧,也许某些方面还存在没完全理解透,还请园友们给予批评指正。 class Program { static void Main(string[] args) { ...阅读全文
posted @ 2011-11-04 09:13 叶鹏 阅读(3772) 评论(42) 编辑
摘要: 很多同学和园友都遇到过sql注入的,其中大部分都是代码的不严谨造成的,都是犯过很多错误才学会认真起来。但是如果是让你接手一个二等残废的网站,并让你在上面改版,而且不能推翻式改版,只能逐步替换旧的程序,那么你会非常痛苦,例如我遇到的问题:问题1. 老板对你说,以前刚做完网站好好了,没有出现木马,怎么你来了,就会出现木马,先别说了,赶紧解决问题,我彻底无语,但是如果争吵,其实证明你和老板一样无知,拿出证据和事实分析来让公司其他稍微懂技术的一起来证明,公司网站被挂马不是你来了的错。如是我通过网站目录仔...阅读全文
posted @ 2011-09-25 16:52 叶鹏 阅读(4173) 评论(42) 编辑
摘要: 自己平时用得比较多tab功能,网上有很强大的tab功能,但是很多时候太过于复杂,所以自己写了一个最简单的jquery插件,代码如下,就不解释了。/* * jqpressToos1.0 * * Copyright (c) 2011 yepeng * Dual licensed under the MIT (MIT-LICENSE.txt) * and GPL (GPL-LICENSE.txt) licenses. * */$.fn.extend({//插件名称:Tab选项卡 jqpressTab: function(options) { //参数和默认值 va...阅读全文
posted @ 2011-09-10 16:01 叶鹏 阅读(606) 评论(2) 编辑
摘要: 小言:这不是设计模式讲解型博文,以下将设计模式的概述、类图,代码示例,总结分每篇博文单独展示,现将其归类,便于以后翻阅,设计模式也不是一两个月学完了就能完全领悟,它只告诉我们几个解决问题的思路和方法,将具体问题抽象为模型的思想,武功也是,套路需要学,但是基本功(如马步、力量,毅力,抗打击能力)绝对不可或缺,在学习设计模式的同时更需要看看数据结构和算法方面的基础东东。设计模式不是银弹,如果非要用降龙十八掌对付一只蚂蚁不是一个好想法。本人也是学艺不精,整理当中难免有错误,希望在大家的批评指正,共同进步。一、创建型模式 ...阅读全文
posted @ 2011-09-08 12:06 叶鹏 阅读(2700) 评论(10) 编辑
摘要: 概述: 访问者模式(Visitor),表示作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素新的操作。适用场合: 1.一个对象结构包含很多类对象,他们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。2.需要对一个对象中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作‘污染’这些对象的类。 visitor使得你可以将相关的操作集中起来定义在一个类...阅读全文
posted @ 2011-09-08 11:08 叶鹏 阅读(348) 评论(0) 编辑