标签 MVC 下的文章

关于在IIS下的.NET网站出现应用池挂掉的Bug排查方法

环境:MVC4+IIS7

现象:测试的时候没有显现出来,当运行到生产环境出现大量访问量的情况下,会出现如下错误:


如果应用程序池挂掉的话,可以肯定的是,代码出现了很严重的错误,导致程序挂了,原因可能是死循环之类的。而又是个别现象引起,测不出来,只能想其他的办法了。

解决方法

首先,在服务器端:

1.开启Windows Error Reporting Service服务

2.执行下面的注册表脚本,在w3wp.exe程序挂掉的时候,自动将dump文件保存到D:\dumps文件夹中:

Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\w3wp.exe]
"DumpFolder"=hex(2):64,00,3a,00,5c,00,64,00,75,00,6d,00,70,00,73,00,00,00
"DumpCount"=dword:00000002
"DumpType"=dword:00000002

3.记录出问题的w3wp.exe程序的pid,把生成的dump文件复制到本地,进行调试。

之后,在本机:

1.双击从服务器上拿下来的dump文件,使用vs(2013、2015等,2010、2008没有测试过)打开,之后会显示出异常摘要等信息。

2.点击右侧“操作”列中的“设置符号路径”菜单

3.通过菜单“视图”——“解决方案资源管理器”,打开解决方案管理器,之后打开解决方案的属性页,选择调试源文件,之后新加一行,选择对应的源代码(项目)文件夹,之后确定保存。

4.回到dump文件摘要页面,通过右侧“操作”菜单下的“使用仅限托管进行调试”菜单进行调试,可以定位到问题代码位置进行解决处理。当然根据问题的不同,还可以选择其他几个调试方法。

以上。

[转]ASP.NET MVC URL重写与优化(进阶篇)-继承RouteBase玩转URL

引言

在初级篇中,我们介绍了如何利用基于ASP.NET MVC的Web程序中的Global文件来简单的重写路由。也介绍了它本身的局限性-依赖于路由信息中的键值对:

如果键值对中没有的值,我们无法将其利用凑出我们想要的URL表达式。
初级篇传送门:使用Global路由表定制URL

在进阶篇中,我们将介绍ASP.NET 路由相关类的基类-抽象类RouteBase,并演示如何通过继承它,让URL重写和优化变成Free Style

一,老板的需求

假设我们是手机销售网站的一名程序猿(承接初级篇),经过第一次的URL重写之后,我们的手机分类页面的URL的改变:

 http://www.xxx.com/category/showcategory?categoryid=0001&view=list&orderby=price&page=1=>http://www.xxx.com/category/0001

现在老板又提出了新的需求,URL的语义化,从而更好的反应网站的结构:

 http://www.xxx.com/ca-categoryname

比如Nokia是一个分类,那么对应URL为 /ca-nokia,如果是iPhone分类,URL则对应 /ca-iphone。ca前缀的意思是分类category

对于这个需求简单的配置Global文件是无法做到的。首先我们来介绍一下ASP.NET 路由的所有类的基类RouteBase

二,RouteBase类简介与运行机制

  1. RouteBase类位于System.Web.Routing命名空间,结构如下:

public abstract class RouteBase
 {
     protected RouteBase();
     public abstract RouteData GetRouteData(HttpContextBase httpContext);
     public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
 }

GetRouteData:根据Http请求信息返回一个对象-包含路由定义的值(如果该路由与当前请求匹配)或 null(如果该路由与请求不匹配)。
GetVirtualPath:检查路由值是否与某个规则匹配,返回一个对象(包含生成的 URL 和有关路由的信息)或 null(如果路由与 values 不匹配)。
RouteBase:初始化该类供继承的类实例使用。此构造函数只能由继承的类调用。

看完以上定义,可能大家会晕忽忽。我们来弄一个简单的例子说明这几个方法是如何运作的。

首先我们新建一个类库JohnConnor.Routing,并且继承抽象类RouteBase

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;//需要添加引用,请使用3.0以上版本 
using System.Web.Routing;
using JohnConnor.Models;
namespace JohnConnor.Routing
{
    public class CategoryUrlProvider:RouteBase
    {
        public override RouteData GetRouteData(System.Web.HttpContextBase httpContext)
        {
            return null;//断点1
        }
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            return null;//断点2
        }
    }
}

这样CategoryUrlProvider类就包含了用来处理路由映射的方法。

首先我们需要在Web程序中添加JohnConnor.Routing类库的引用,然后我们把CategoryUrlProvider类注册到Global文件的路由表中。

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.Add(new JohnConnor.Routing.CategoryUrlProvider());//分类规则
    routes.MapRoute("Home", "", new { controller = "Home", action = "Index"});//主页
}

这里相当于添加了一条新的路由规则。重新生成一下Web程序在CategoryUrlProvider中打好断点,F5启动。

  2. GetRouteData()方法

这时候相当与你在浏览器输入了http//localhost:1234/<假设本地端口号是1234>,此时程序需要判断这个URL匹配的是哪个路由值。

自上而下的匹配,首先会尝试匹配我们新增的分类路由规则,此时会命中GetRouteData()方法中的断点。

因为我们返回了null,意味着该请求与我们新增的分类路由规则不匹配,那程序将在路由表中继续自上而下的进行匹配。

直到在主页这一条规则中与其URL表达式匹配,获取了对应的路由值-调用HomeController.Index()方法。
如果你把GetRouteData()方法修改一下:

public override RouteData GetRouteData(System.Web.HttpContextBase httpContext)
{
    var data = new RouteData(this, new MvcRouteHandler());
    data.Values.Add("controller", "Home");
    data.Values.Add("action", "Index");
    return data;
}

你就会发现,无论你在 http//localhost:1234/ 后面输入任何相对URL,都会被定向到HomeController.Index()方法。

因为返回的是路由值而不是null,表示已经找到匹配项,就不会再往下匹配了。<这条规则覆盖了后面所有的规则>

当然,请不要这样写。。。

由此可以推断出GetRouteData()方法在路由映射中担任的角色:处理请求中的URL,返回相应的路由值,不处理或不匹配则返回null。

  3. VirtualPathData()方法

如果你在Razor页面有这样一段通过指定路由值来获取URL的代码

<a href="@Url.Action("Index", "Home")">首页</a>

当视图引擎渲染页面到这句代码时,HomeController.Index()方法会被解析为一个RouteValueDictionary类型的不分大小写的键值对<假设键值对对象为values>:

values["controller"]="Home";
values["action"]="Index";

这个键值对表示了一个路由值。

同样是在路由表中自上而下的匹配这个路由值,尝试第一条分类规则时,就会命中VirtualPathData()方法中的断点。

我们返回一个null,表示不匹配,则程序进行下一个规则的匹配。

直到找到主页规则的路由值与之匹配时,构造出相应的相对URL"",并返回该URL。

显示为:

<a href="http://localhost:1234/">首页</a>

如果我们也改写一下VirtualPathData()方法:

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
  return new VirtualPathData(this, "This-is-a-Test-URL");
}

结果是你通过上述方法构造的URL不论请求来自哪里,全部都会显示成http://localhost:1234/This-is-a-Test-URL

因为我们返回的是一个相对路径,而不是null,表示已经找到匹配项,则匹配不会往下继续。<同上这条规则覆盖了后面所有的规则>

再一次提示,请不要这样写。。。

由此可看出,VirtualPathData()在路由映射中的活:处理请求与路由键值对,生成相应URL,不处理或不匹配则返回null。

  4.方法重写的规则

  在上文中,我一再的用红色字体提示,请不要这样写。因为每一个URL的重写类,建议仅仅处理尽可能少的路由映射。

比如CategoryUrlProvider仅处理CategoryController.Show(string categoeyid)这一个Action方法的映射。凡是不是这个方法相关的映射,都返回null。

继续去匹配别的规则。

三,开始动手把~

  为了最快的说明问题,我们简化了网站的内容。以下内容有助于理解后面的程序,如果时间充裕,还是自己构建一个网站来尝试以下。
首先我们在JohnConnor.Routing类库中创建Category.cs来保存分类模型,并把所有的分类显示的保存在 List < Category >中,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace JohnConnor.Models
{
    //分类模型
    public class Category
    {
        public string CategoeyID { get; set; }
        public string CategoeyName { get; set; }
    }
    public static class CategoryManager
    {
        //这里只显示创建了三个分类作为示例,实际中AllCategories可以从数据源读取。
        public static readonly List<Category> AllCategories = new List<Category>
        {
            new Category(){ CategoeyID="001", CategoeyName="Nokia"},
            new Category(){ CategoeyID="002", CategoeyName="iPhone"},
            new Category(){ CategoeyID="003", CategoeyName="Anycall"}
        };
    }
}

假设我们网站的CategoryController是这样的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using JohnConnor.Models;
namespace JohnConnor.Web.Controllers
{
    public class CategoryController : Controller
    {
        public ActionResult ShowCategory(string id)
        {
            var category = CategoryManager.AllCategories.Find(c => c.CategoeyID == id);
            return View(category);
        }
    }
}

首先我们建议,VirtualPathData()GetRouteData()方法是成双成对出现的。一旦你制定了一条路由规则,比如分类规则/ca-categoryname,那么:

GetRouteData()必须处理与这条规则匹配的每一条URL,返回相同的路由值;放弃与之不匹配的URL,返回null,让匹配继续。
VirtualPathData()必须处理与这条规则匹配的每一次路由请求,返回相同的URL;放弃与之不匹配的请求,返回null,让匹配继续。

!!!两者相辅相成的完成了路由值和URL的相互映射,漏掉一个,就不能构成一个完成的路由规则。直接结果是出现404或生成URL地址错误。

GetRouteData()的代码:

public override RouteData GetRouteData(System.Web.HttpContextBase httpContext)
{
    var virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath + httpContext.Request.PathInfo;//获取相对路径
   virtualPath = virtualPath.Substring(2).Trim('/');//此时URL会是~/ca-categoryname,截取后面的ca-categoryname
    if (!virtualPath.StartsWith("ca-"))//判断是否是我们需要处理的URL,不是则返回null,匹配将会继续进行。
        return null;
    var categoryname = virtualPath.Split('-').Last();//截取ca-前缀后的分类名称
   //尝试根据分类名称获取相应分类,忽略大小写
    var category = CategoryManager.AllCategories.Find(c => c.CategoeyName.Equals(categoryname,StringComparison.OrdinalIgnoreCase));
    if (category == null)//如果分类是null,可能不是我们要处理的URL,返回null,让匹配继续进行
        return null;
    //至此可以肯定是我们要处理的URL了
    var data = new RouteData(this, new MvcRouteHandler());//声明一个RouteData,添加相应的路由值
    data.Values.Add("controller", "Category");
    data.Values.Add("action", "ShowCategory");
    data.Values.Add("id", category.CategoeyID);
    return data;//返回这个路由值将调用CategoryController.ShowCategory(category.CategoeyID)方法。匹配终止
}

VirtualPathData()的代码

public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
    //判断请求是否来源于CategoryController.Showcategory(string id),不是则返回null,让匹配继续
    var categoryId = values["id"] as string;
    if (categoryId == null)//路由信息中缺少参数id,不是我们要处理的请求,返回null
        return null;
    //请求不是CategoryController发起的,不是我们要处理的请求,返回null
    if (!values.ContainsKey("controller") || !values["controller"].ToString().Equals("category",StringComparison.OrdinalIgnoreCase))
        return null;
    //请求不是CategoryController.Showcategory(string id)发起的,不是我们要处理的请求,返回null
    if (!values.ContainsKey("action") || !values["action"].ToString().Equals("showcategory", StringComparison.OrdinalIgnoreCase))
        return null;
    //至此,我们可以确定请求是CategoryController.Showcategory(string id)发起的,生成相应的URL并返回
    var category = CategoryManager.AllCategories.Find(c => c.CategoeyID == categoryId);
    if (category == null)
        throw new ArgumentNullException("category");//找不到分类抛出异常
    var path = "ca-" + category.CategoeyName.Trim();//生成URL
    return new VirtualPathData(this, path.ToLowerInvariant());
}

至此,我们就把这条路由规则的映射处理完整了。如果你掌握了上述技术,任何的URL重写和优化需求,我相信你都能Hold住。

如果我们的主页页面是这样 < Razor视图引擎 > :

@model List<JohnConnor.Models.Category>
@{
    ViewBag.Title = "主页";
}
<h2><a href="@Url.Action("Index", "Home")">首页</a></h2>
<p>
@foreach (var item in Model)
{
      <a href="@Url.Action("ShowCategory", "Category", new { id = item.CategoeyID })">@item.CategoeyName</a>
}
</p>

三个分类连接会得到这样的结果

<a href="/ca-nokia">Nokia</a>
<a href="/ca-iphone">iPhone</a>
<a href="/ca-anycall">Anycall</a>

点击每一个连接都会先进入我们的处理程序,生成相应的路由值-调用CategoryController.Showcategory(string id)方法根据id显示相应的分类页面。

------------------------------------------------------进阶篇完---------------------------------------------------

这一篇我花费了不少时间去构思如何用简单的例子讲述继承RouteBase来进行URL重写与优化。
希望能帮助到有用的人。
需要程序源代码朋友点这里: 201607171468761839914037.rar
如有任何问题,欢迎指正和讨论。
原文:http://www.cnblogs.com/john-connor/archive/2012/05/03/2478821.html

分类

最新文章

最近回复

  • 老徐: 已经加上了,抱歉才看到
  • 青山: 某种原因,暂停友链,抱歉。
  • 搬瓦工: 朋友 交换链接吗
  • 飞刀说: 名称:飞刀说 描述:...
  • 青山: 计划搬迁到腾讯云,正...
  • 河边的飞刀: 网站名称:飞刀说 网...
  • 老徐: 具体要哪个呢?
  • 老徐: 是不是有点老?
  • 青山: 哇,林志炫
  • 老白: 哇,这改的可以,能不...

归档

标签云

C# .net core asp.net 情感 SQL mongodb sql server EasyUI 安全 激活 linux 身份验证 https typecho .net sql注入 kms MVC IIS 高并发 IE 坑爹 服务器 mysql Oracle Combobox Datagrid 口语 数据抓取

其它