ASP.NET路由[ASP.NET Routing]

时间:2022-09-05 14:42:24

ASP.NET路由[ASP.NET Routing]

  ASP.NET路由允许你在使用URL时不必匹配到网站中具体的文件,因为这个URL不必匹配到一个文件,你使用了描述用户行为且更容易被用户理解的URL。

  ASP.NET MVC框架和ASP.NET动态数据(Dynamic Data)扩展路由为MVC应用和动态数据应用增加了特色。

  在不使用路由的ASP.NET应用中,一个新的请求会被映射到一个物理文件并由该文件处理这个请求,例如一个.aspx文件。例如,如下请求http://server/application/Products.aspx?id=4会题映射到一个包含代码和标签来向浏览器渲染响应的Products.aspx文件。Web页面人员使用id=4的查询字符来确定显示的内容。

  使用ASP.NET路由,你可以定义映射请求-处理程序(request-handler)文件的URL模式,但没必要在将这些文件的名字包含在这个URL中。除此之外,你还可以通过在URL模式中使用占位符来向请求处理程序传输变量数据,而不必使用查询字符串。

  例如,如下请求 http://server/application/Products/show/beverages,路由分析器会向页面处理器传入Products,show,beverages这些值。在这个例子中,如果使用server/application/{area}/{action}/{category}URL模式定义路由,页面处理器将会收到一个字典集合,这个集合中包含以下键值对,area:Products,action:show,category:beverages。如果是在一个不被URL路由管理的请求中,/Products/show/beverages片断将会被当作应用中的一个文件路径解释执行。

一、      路由[Routes]

  路由是被处理程序映射的URL模式。处理程序可以是一个物理文件,例如Web Form应用中的.aspx文件。处理也可以是处理请求的类,例如MVC应用中的控制器。为了定义一个路由,你需要创建一个Route类的实例来指定URL模式,处理程序和可选的路由名称。

  你需要给RouteTable类的Routes静态属性添加Route对象来为应用添加路由。Routes属性是一个RouteCollection对象,其中存放着应用中所有路由规则。

  你通常没有必要为MVC应用编写代码添加来添加路由规则。Visual Studio的MVC项目模板包含了预配置的URL路由规则。他们定义在MvcApplication类,这个类在Global.asax文件中。

二、      URL模式[URL Patterns]

  一个URL模式可以包含字面值(literal)和可变的占位符(参考URL参数)。这些字面值和占位符在URL片断中通过斜线(/)字符来分开和定位。

  当一个请求到达,这个URL被解析成片断和占位符,这些变量会提供给请求处理器。这个过程和将数据通过查询字符串(query strings)中解析和传输至请求处理器很类似。这两种情况下变量信息都会包含在URL中并传到处理程序的键值对的表单中。对于查询字符串而言,所有键(keys)和值(values)都包含在URL中。对于路由方式,所有键就是在URL模式中定义的占位符名称,只有值包含中URL中。

  在一个URL模式中,你定义的占位符被大括号包裹起来({and})。你可以在一个片断中定义多个占位符,但是它们必须被字面值分隔开。例如,{language}-{country}/{action}就是一个合法的路由模式。然而{language}{country}/{action}不是一个合法的路由模式,因为它们的占位符之间缺少字面值或分隔符。因此,路由无法确定language和country占位符的值是何处分隔。

  下表给出了合法的路由模式,以及其各自能正确匹配的URL请求。

路由定义

匹配URL示例

{controller}/{action}/{id}

/Products/show/beverages

{table}/Details.aspx

/Products/Details.aspx

blog/{action}/{entry}

/blog/show/123

{reporttype}/{year}/{month}/{day}

/sales/2008/1/5

{locale}/{action}

/US/show

{language}-{country}/{action}

/en-US/show

MVC应用中标准的URL模式[Typical URL Patterns in MVC Applications]

  在MVC应用中,路由标准的URL模式包含{controller}和 {action}占位符。

  当接收到一个请求时,它先被发送到UrlRoutingModule对象,再发送到MvcHandler HTTP处理程序。MvcHandler HTTP处理程序确定需要执行的控制器,通过给URL中的controller值添加”Controller”后缀从而确定将处理本次请求的控制器类型名称。URL中的action值确定调用的处理方法。

  例如,URL路径 /Products会被映射成ProductsController控制器。action参数的值是被调用的处理方法的名称。URL路径/Products/show的映射结果将会是调用类ProductsController 的方法Show。

  下表给出了默认的URL模式和它们能处理的URL请求示例。

默认URL模式

匹配URL示例

{controller}/{action}/{id}

http://server/application/Products/show/beverages

{resource}.axd/{*pathInfo}

http://server/application/WebResource.axd?d=...

  路由使用模式 {resource}.axd/{*pathInfo} 来阻止对网络文件的请求,例如WebReource.axd,ScriptResource.axd被传递给一个控制器。

  对于IIS7.0,可以不用扩展名。对于IIS6.0,你必须将扩展名.mvc添加到URL模式,如下所示:{controller}.mvc/{action}/{id}

三、      为Web Forms应用程序添加路由[Add Routes to a Web Forms Application]

  在Web Form应用中,你可以使用类RouteCollection的方法MapPageRoute(String, String, String) 创建路由。方法MapPageRoute创建Route对象并将其添加RouteCollection对象中。你需要为Route对象在参数在指定一些属性,用来传给方法MapPageRoute

  通常情况下,你在方法中添加的路由会被Global.asax文件中Application_Start 方法处理器调用。这种方法确保了这些路由在应用程序启动时可以正常调用。它也允许你在为应用程序做单元测试时可直接调用该方法。当你在做单元测试时如果想要直接调用一个方法,该方法在注册时就必须是静态(Visual Basic中Shared)且有一个RouteCollection参数。

  下例中演示了Global.asax文件中添加一个Route对象,该对象定义了action和categoryName两个参数。URL中还定义了一个被定向到名为Categories.aspx的物理页面。

protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
} public static void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute("",
"Category/{action}/{categoryName}",
"~/categoriespage.aspx");
}

四、      为MVC应用程序添加路由[Adding Routes to an MVC Application]

  在MVC应用程序中,如果你采用MVC实现控制器的约定,即派生自类ControllerBase且以“Controller”结尾命名,那么你根本不需要搬运添加路由。预配置的路由将会执行你实现的控制器类中的处理方法。

  如果你希望在MVC应用程序中添加自定义的路由,你可以使用方法MapRoute(RouteCollection, String, String) 来取代方法MapPageRoute(String, String, String)

  下面示例中演示在Global.asax文件中创建默认MVC路由的代码,即是Visual Studio中MVC应用程序的项目模板。

public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
); } protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
}

五、      为URL参数设置默认值[Setting Default Values for URL Parameters]

  当你定义一个路由时,你可以为参数指定一个默认值。如果一个参数的值不在URL中,则使用默认值。给路由设置默认值时是给类Route的属性Defaults指定一个字典对象。下例演示了如何使用方法MapPageRoute(String, String, String, Boolean, RouteValueDictionary)添加一个包含默认值的路由。

void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
} public static void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute("",
"Category/{action}/{categoryName}",
"~/categoriespage.aspx",
true,
new RouteValueDictionary
{{"categoryName", "food"}, {"action", "show"}});
}

  下图中演示了ASP.NET路由处理URL请求,路由定义(categoryName的默认值为food,action默认为show)和解析结果:

URL

Parameter values

/Category

action = "show" (default value)

categoryName = "food" (default value)

/Category/add

action = "add"

categoryName = "food" (default value)

/Category/add/beverages

action = "add"

categoryName= "beverages"

  对于MVC应用程序,方法RouteCollectionExtensions.MapRoute的重载版本,如MapRoute(RouteCollection, String, String, Object, Object),允许你指定默认值。

六、      URL模式中处理可变数量片断[Handling a Variable Number of Segments in a URL Pattern]

  有时候你必须处理包含可变个数的URL片断的URL请求。当你定义一个路由时,你可以指定当一个URL拥有比模式中还要多的片断时,额外的片断会被当作最后一个片断对待。你需要为最后一个参数添加一个星号(*)来用这种方式处理额外的片断。这被称作全匹配(catch-all)参数。包含全匹配参数也将匹配最后参数不带任何值的URL。下例展示一个可以匹配无法确定片断长度的路由模式。

  query/{queryname}/{*queryvalues}

  下图中演示了ASP.NET路由处理URL请求,路由定义和解析结果。

URL

Parameter values

/query/select/bikes/onsale

queryname = "select"

queryvalues = "bikes/onsale"

/query/select/bikes

queryname = "select"

queryvalues = "bikes"

/query/select

queryname = "select"

queryvalues = Empty string

七、      为路由添加约束[Adding Constraints to Routes]

  路由模式中除了定义了可匹配URL请求的参数个数,还可以指定这些参数的值需要满足的某些约束。如果一个URL中的参数值不符合一个路由的约束,那么此路由不会处理该请求。你添加的约束条件是为了确保URL参数中包含的值能在你的应用程序中工作。

  约束条件是用正则表达式或实现了接口IRouteConstraint的对象来定义。当你将一条路由添加进Routes 集合时,你可以添加包含验证测试的对象RouteValueDictionary约束条件。字典中的键唯一标识符合约束条件的参数。字典中的值既可以是符合正则表达式的字符串,也可以是实现接口IRouteConstraint的对象。

  如果你提供一个字符串,路由会将它当作符合正则表达式的值,并调用Regex类的IsMatch()方法检查该参数值是否符合规则。正则表达式总是不区分大小写检查。

  如果你提供了一个IRouteConstraint对象,ASP.NET路由调用IRouteConstraint对象的Match()方法来检查参数值是否合法。Match()方法返回布尔值来表明参数值是否合法。

  下例中演示如何利用方法MapPageRoute 添加一条路由,并为参数locale和year添加约束。(MVC应用程序中,使用方法MapRoute。)

public static void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute("",
"Category/{action}/{categoryName}",
"~/categoriespage.aspx",
true,
new RouteValueDictionary
{{"categoryName", "food"}, {"action", "show"}},
new RouteValueDictionary
{{"locale", "[a-z]{2}-[a-z]{2}"},{"year", @"\d{4}"}}
);
}

  当路由处理URL请求时,例子中路由的定义和解析后的结果如下表所示:

URL

Result

/US

No match. Both locale and year are required.

/US/08

No match. The constraint on year requires 4 digits.

/US/2008

locale = "US"

year = "2008"

八、      路由不起作用的情况[Scenarios When Routing Is Not Applied]

  在某些情况下,ASP.NET路由即使可用也不会处理请求。这节将介绍几种路由不会处理请求的情况。

URL模式匹配一个有效的物理文件[A Physical File is Found that Matches the URL Pattern]

  默认情况下,路由不会处理请求时,将其映射到Web服务器上一个已存在的物理文件。例如,如果存在一个物理文件Products/Beverages/Coffee.aspx,路由就不会处理请求http://server/application/Products/Beverages/Coffee.aspx。路由即使如下定义{controller}/{action}/{id},也能匹配该请求,它也不会处理该请求。

  如果你希望路由能处理所有请求,即使请求指向一个文件,你可以通过设置对象RouteCollection的属性RouteExistingFilestrue来重写默认行为。当你将这个值设置为true则所有与定义路由模式匹配的请求都会被路由处理。

显式禁用路由[Routing Is Explicitly Disabled for a URL Pattern]

  你也可以指明路由不处理某些URL请求。定义一个路由并指明由类StopRoutingHandler处理该模式,以阻止路由处理某些请求。当一个请求被StopRoutingHandler对象处理时,StopRoutingHandler对象块会为请求添加一些额外的信息。相反,这个请求会被当作一个ASP.NET页面、Web服务或是其他ASP.NET终端处理。你可以使用方法RouteCollection.Ignore(MVC应用程序中RouteCollectionExtensions.IgnoreRoute)来创建使用类 StopRoutingHandler的路由。下面演示如何阻止对WebResource.axd文件的请求。

public static void RegisterRoutes(RouteCollection routes)
{
routes.Ignore("{resource}.axd/{*pathInfo}");
}

  URL是如何被路由匹配的[How URLs Are Matched to Routes]

  当路由开始处理URL请求时,它为尝试着将请求匹配到一条路由规则上。一条路由规则能否匹配URL请求取决与以下条件:

    • 在你的项目中是否包含自定义的路由规则或者默认路由。
    • 集合Routes中添加路由规则的顺序。
    • 为路由规则添加的默认值。
    • 为路由规则添加的约束。
    • 是否定义了匹配对物理文件请求的路由。

  为了避免不合适的路由处理了请求,在定义路由规则时一定要考虑所有这些条件。集合 RoutesRoute对象出现的顺序也应仔细思考。路由集合中从第一项到最后一项依次尝试的路由匹配。当有一个匹配成功,不再对后续路由尝试匹配。通常,添加路由时应先添加最具体的,最后添加最不明确的规则。

  例如你添加了如下路由规则:

    • 路由规则1,{controller}/{action}/{id}
    • 路由规则2, products/show/{id}

  路由2绝不会处理请求,因为路由1会最先尝试匹配,并且与路由2匹配的请求在它上面也总是可以工作。例如请求http://server/application/products/show/bikes看起来好像和路由2更匹配,但是它会被路由1解析,解析结果如下:

    • controller is products.
    • action is show.
    • id is bikes.

  当请求的参数缺少时,默认值就能起作用。然而,它们可能会匹配到并非你所愿的请求。例如,假如添加如下两条路由规则:

    • 路由1:{report}/{year}/{month},year,month带有默认值。
    • 路由2:{report}/{year},year有默认值。

  路由2将绝无处理请求的机会。路由1希望能按月份匹配,而路由2则希望是按年度。但是,路由1中的默认值会让所有匹配路由2的请求在路由1中也能工作。

  你可以在路由中包含常量来避免这种歧义,例如annual/{report}/{year}和monthly/{report}/{year}/{month}。

  如果一个URL不能匹配到在RouteTable集合中的任何一个Route对象,ASP.NET路由将不会处理该请求。

九、      从路由创建URL[Creating URLs from Routes]

  如果你想要创建一个链接到你站点页面的超链接,你可以使用URL模式编程创建符合路由的URL。当你修改了路由模式,URL会自动匹配到新的模式上。

十、      在路由页面访问URL参数[Accessing URL Parameters in a Routed Page]

参见:https://msdn.microsoft.com/en-us/library/dd535620.aspx

https://msdn.microsoft.com/en-us/library/dd394711.aspx

十一、      配置路由环境[Configuration Settings for Routing]

  ASP.NET中,要让应用程序支持路由功能,需要添加如下配置:

<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<!-- more -->
</modules>
</system.webServer>
</configuration>

  当runAllManagedModulesForAllRequests为true时,如下URLhttp://mysite/myapp/home,即使URL中没有.aspx,.mvc或者其他扩展名,该请求也能到达ASP.NET。

  然而,IIS7的更新导致不必添加配置项runAllManagedModulesForAllRequests,因为它本来就支持ASP.NET路由功能。

  如果你的站点运行在IIS7且IIS已更新,你就不必设置该配置项为true。事实上,并不推荐设置它,因为它为所有请求增加了不必要的操作。如果设置该配置为true,所有请求,包括.htm,.jpg和其他静态文件都会通过ASP.NET请求通道。

  默认runAllManagedModulesForAllRequests为false。如果网站配置文件中没有明确将其设置为true,而你又在未安装SP1的Windows 7,不包含必要更新的IIS7中运行你的网站。 结果就是,你会看到路由不会工作的错误提示。如果路由中存在一些问题,你可以试试下面的方法:

    • 将Windows 7更新到SP1,因为它添加了IIS7的更新。
    • 安装微软件在先前文章中的描述的更新。
    • 在Web.Config文件中设置runAllManagedModulesForAllRequests为true。注意这会添加一些额外开销。

十二、      ASP.NET路由与安全性[ASP.NET Routing and Security]

  授权规则可应用于单独映射的路由URL或同时映射的路由URL和物理URL。例如,授权规则可以声明所有用户都可以访问以开头Category的URL,但是只有管理员才能访问Categories.aspx页面。如果路由URL模式contoso.com/Category/{controller}/{action} 映射到物理地址contoso.com/Categoriespage.aspx,你只能为路由地址添加授权规则,当用一个路由地址请求过之后,所有用户都被允许可访问Categoriespage.aspx。然而,当使用物理地址请求之后,只有管理才有权限访问。

  默认情况下,授权规则应用于路由地址和物理地址。

十三、      ASP.NET Web Form和路由安全性[ASP.NET Web Forms and Route Security]

  在ASP.NET Web窗体应用程序中,你不应该将站点的安全性全寄托在路由授权规则,因为它们可能留下一些未保护处理的物理地址。

十四、      ASP.NET MVC和路由安全性[ASP.NET MVC and Route Security]

  你不能使用路由或web.config文件保证MVC应用程序的安全性。唯一能保证MVC应用安全的做法是给所有控制器应用特性 AuthorizeAttribute ,并在登录和注册的方法(action)上应用特性AllowAnonymousAttribute 。

  扩展请查看:http://blogs.msdn.com/b/rickandy/archive/2012/03/23/securing-your-asp-net-mvc-4-app-and-the-new-allowanonymous-attribute.aspx

十五、      参考类[Class Reference]

Class

Description

Route

Represents a route in a Web Forms or MVC application.

DynamicDataRoute

Represents a route in a Dynamic Data application.

RouteBase

Serves as the base class for all classes that represent an ASP.NET route.

RouteTable

Stores the routes for an application.

RouteCollection

Provides methods that enable you to manage a collection of routes.

RouteCollectionExtensions

Provides additional methods that enable you to manage a collection of routes in MVC applications.

RouteData

Contains the values for a requested route.

RequestContext

Contains information about the HTTP request that corresponds to a route.

StopRoutingHandler

Provides a way to specify that ASP.NET routing should not handle requests for a URL pattern.

PageRouteHandler

Provides a way to define routes for Web Forms applications.

RouteValueDictionary

Provides a way to store route ConstraintsDefaults, and DataTokensobjects.

VirtualPathData

Provides a way to generate URLs from route information.

十六、      ASP.NET路由VS URL重写[ASP.NET Routing versus URL Rewriting]

  ASP.NET路由与URL重写不同。URL重写方式处理到达的请求时,先修改其URL再将请求发送至Web页面。例如,一个应用程序中可能使用URL重写将/Products/Widgets/修改为/Products.aspx?id=4。同时,URL重写的特点是没有基于你的模式创建URL的API。使用URL重写,如果你需要个性URL规则,你不得不手动更新所有相关联的超链接。

  使用ASP.NET路由,在处理到达的请求时URL不会发生变化,因为路由功能可能从URL中提取值。当你需要创建一个URL时,给一个方法传入参数值就能为你生成URL。修改URL规则,只需要调整一个地方,你在应用程序中创建的所有链接都会自动使用新规则。

  源地址:https://msdn.microsoft.com/en-us/library/cc668201.aspx?cs-save-lang=1&cs-lang=csharp#aspnet_routing_versus_url_rewriting

ASP.NET路由[ASP.NET Routing]的更多相关文章

  1. 返璞归真 asp&period;net mvc &lpar;2&rpar; - 路由&lpar;System&period;Web&period;Routing&rpar;

    原文:返璞归真 asp.net mvc (2) - 路由(System.Web.Routing) [索引页] [源码下载] 返璞归真 asp.net mvc (2) - 路由(System.Web.R ...

  2. ASP&period;NET路由模型解析

    大家好,我又来吹牛逼了 ~-_-~ 转载请注明出处:来自吹牛逼之<ASP.NET路由模型解析> 背景:很多人知道Asp.Net中路由怎么用的,却不知道路由模型内部的运行原理,今天我就给大家 ...

  3. Asp&period;Net MVC 路由 - Asp&period;Net 编程 - 张子阳

    http://cache.baiducontent.com/c?m=9d78d513d98316fa03acd2294d01d6165909c7256b96c4523f8a9c12d522195646 ...

  4. ASP&period;NET没有魔法——ASP&period;NET MVC 路由的匹配与处理

    ASP.NET MVC的路由是MVC应用的一个核心也是MVC应用处理的入口,作为一个开发者,在正常情况下仅仅需要做的就是根据需求去定义实体.业务逻辑,然后在MVC的Controller中去调用.Vie ...

  5. ASP&period;NET Web API 框架研究 ASP&period;NET 路由

    ASP.NET Web API 如果采用Web Host方式来寄宿,在请求进入Web API 消息处理管道之前,就会用ASP.NET 自身的路由系统根据注册的路由表,解析出当前请求的HttpContr ...

  6. ASP&period;NET MVC &comma; ASP&period;NET Web API 的路由系统与 ASP&period;NET 的路由系统是怎么衔接的&quest;

      ASP.NET MVC 的路由实际上是建立在 ASP.NET 的路由系统之上的. MVC 路由注册通常是这样的: RouteTable 是一个全局路由表, 它的 Routes 静态属性是一个 Ro ...

  7. 我的IIS7&period;5竟然不支持ASP&period;NET路由

    MVC模式下那些友好,屏蔽具体物理文件的URL让我眼馋,咱也想在WEB FORM项目用上一用. 按照指引,添加global.asax,写上路由代码什么的: <%@ Application Lan ...

  8. ASP&period;NET Core 路由 - ASP&period;NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core 路由 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 路由 前两章节中,我们提到 ASP.NET Core 支持 MVC 开发 ...

  9. 路由 - ASP&period;NET MVC 4 系列

           软件开发人员常常对一些细小的细节问题倍加关注,由其在考虑源代码的质量和结构时更是如此.因此,当遇到大部分使用 ASP.NET 技术构建的站点,使用如下的 URL 地址时,可能会有些奇怪: ...

随机推荐

  1. Linux上性能异常定位以及性能监控

    引言:大多数的服务都是跑在Linux上的,Linux现在也已经到了一个很广泛的应用,但是仍然会有很多问题出现,我们就来讨论下我们性能监控的指标,性能监控无非就是从I/O,内存,CPU,TCP连接数,网 ...

  2. 疯狂java学习笔记之面向对象&lpar;一&rpar; - 定义类、方法、构造器

    Java面向对象 1.定义类 2.创建对象.调用方法 类和对象: 某一类对象的概念定义. 比如:人类 - 抽象出来的概念(不特指某个人) 对象 - 在类的概念下产生的一个实例,它就是一个对象了. ja ...

  3. Redis和Memcached对比

    Redis和Memcached对比 这两年 Redis火得可以,Redis也常常被当作 Memcached的挑战者被提到桌面上来.关于Redis与Memcached的比较更是比比皆是.然而,Redis ...

  4. 利用decorator和descriptor进行数据缓存

    class cached_property(object): def __init__(self, func, name=None, doc=None): self.__name__ = name o ...

  5. Scala Tuple类型

    Tuple可以作为集合存储不同类型的数据,初始化实例如下: val tuple = (1,3,3.14,"aa") val third = tuple._3 Tuple 下标访问从 ...

  6. HDU 1064&lpar;求平均数 &ast;&ast;&rpar;

    题意是求 12 个浮点数的平均数,这题不用读题,看到运行时间为 200 ms 再看下样例就能猜出题目的要求了,代码如下: #include <bits/stdc++.h> using na ...

  7. Java 递归获取一个路径下的所有文件,文件夹名称

    package com.readfile; import java.io.File; public class GetAllFiles { public static void main(String ...

  8. django中form组件

    Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...

  9. stenciljs 学习十二 官方doc 路由使用的例子

    路由在单页面应用开发中是一个相对比较重要的位置 以下为官方网站的路由配置 <stencil-router scrollTopOffset={0}> <stencil-route-sw ...

  10. Xamarin C&num; Android for Windows 安装

    Xamarin C# Android for Windows  安装 Xamarin的. Android手动安装 安装Xamarin的  Android在Windows机器上   大多数时候,Xama ...