未能初始化 AppDomain:/LM/W3SVC/1/Root,未能加载文件或程序集“System.Web.

mikel阅读(1238)

更新了dll后提示:

未能初始化 AppDomain:/LM/W3SVC/1/Root,未能加载文件或程序集“System.Web.

重启后IIS好了

开发的项目在vs2005开发环境下就可以运行,没有一点错,但是放到IIS浏览的时候就出错
页面错误提示如下:
服务器应用程序不可用
您试图在此 Web 服务器上访问的 Web 应用程序当前不可用。请点击 Web 浏览器中的“刷新”按钮重试您的请求。
查看系统事件日志,发现一个错误和一个警告
错误:
由于无法创建应用程序域,因此未能执行请求。错误: 0x80070005 拒绝访问。
警告:
未能初始化 AppDomain:/LM/W3SVC/…
Exception: System.IO.FileLoadException
Message: 未能加载文件或程序集“System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”或它的某一个依赖项。拒绝访问。
在网上查找了一圈,发现好像无论是2003还是xp都会出现这种问题,产生问题的原因有:1、ASP.NET2.0没有正确地在IIS中注册 2、权限问题
如果是第一种情况,可以重新注册ASP.NET:系统盘\windows\microsoft.net\framework\v2.0.50727([color=#0080ff]此处为版本号[/color])\aspnet_regiis.exe -i
如果是权限问题,需要确保ASP.NET运行帐户(默认情况下,在win2003中是Network Service,在xp中是aspnet)对N个目录具有相应的访问权限,主要是系统目录(具体列表可以在网上很容易找到),还有一个容易忽略的目录:

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(1)

mikel阅读(1011)

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(1) – 刘铭.net-OPS.cc – 博客园.

一般处理程序(.ashx)比Web窗体文件(.aspx)性能更好,再不涉及到html的场景中经常用到!

通过VS创建的ashx文件包括代码后置文件,而实际上在ashx文件中定义只需要声明Web Handler并添加class

如: <%@ WebHandler Class=”Web.Handler” %>

我们可以在项目里面创建一个实现IHttpHandler接口的类,然后将ashx文件class设为该类的名称,这样维护起来是不是更方便?

大多数的同学可能就直接在IHttpHandler的ProccessRequest(HttpContext context)方法中添加自己的代码了,但如果网站包含50个ashx文件的话又会怎么样呢?下面我来阐述一个思路

我们是否可以将要请求的代码包含在一个个的类里,然后在ProccessRequest方法里利用反射技术执行代码就好了呢?

反射,程序员的快乐!

下面我们一步一步开始实现我们的想法:

首先我们需要为被执行代码添加授权,表明他能通过WebHandler执行,要不然就能通过WebHandler执行类库里的任何类!

1 代码:WebExecuteAttribute.cs
2 namespace HuiShi.Web
3 {
4 using System;
5 [AttributeUsage(AttributeTargets.Class,AllowMultiple=false,Inherited=true)]
6 public class WebExecuteAttribute : Attribute{}
7 }
8
9 }
东方网新,为您提供专业的网站建设,软件开发,网络营销SEO,网络推广服务,代理国外主机空间,域名注册,服务热线:(+86)18608275575,电子邮件:master#atnet.cc;欢迎您访问东方网新网站:www.atnet.cc

下面该是反射技术大展神手的时候了!先说明一下我们请求的URI格式如下:

http://localhost:11080/exc.ashx?cmd=IPQuery,GetNameByAddress,127.0.0.1

参数以”,”格开,IPQuery为类,GetNameByAddress为IPQuery的方法,GetNameByAddress后的为方法的参数

实际上执行的代码为:

01 namespace HuiShi.Web
02 {
03 using System;
04 using System.Web;
05
06 [WebExecute]
07 public class IPQuery
08 {
09 public string GetNameByAddress(string address)
10 {
11 return “newmin’s website www.atnet.cc“;
12 }
13 }
14 }

在代码中通过”,”来将参数传给方法,并判断方法的返回值是否可以输出到页面,可以的话就输出到页面!

01 代码:ExecuteHandler.cs
02
03 namespace HuiShi.Web
04 {
05 using System;
06 using System.Web;
07 using System.Reflection;
08 using System.Collections.Generic;
09
10 public class ExecuteHandler : IHttpHandler
11 {
12
13 #region IHttpHandler 成员
14 public bool IsReusable{ get; set; }
15 public void ProcessRequest(HttpContext context)
16 {
17 string cmd=context.Request["cmd"].Replace(“+”,” “); //将空格做为+号替换
18
19 string[] args = cmd.Split(‘,’);
20 if (args.Length > 2)
21 {
22 //获取执行当前代码的程序集并创建实例
23 Assembly ass = Assembly.GetAssembly(this.GetType());
24 object obj = ass.CreateInstance(this.GetType().Namespace+”.”+args[0], true);
25
26 //获取实例类型
27 Type type=obj.GetType();
28
29 //未添加WebExecuteAttribute特性的类将不被执行
30 object[] attrs= type.GetCustomAttributes(typeof(WebExecuteAttribute), false);
31 WebExecuteAttribute attr =attrs.Length>0?attrs[0] as WebExecuteAttribute:null;
32 if (attr == null) { context.Response.Write(“此模块不允许被执行!”); return; }
33
34 //获取方法并执行
35 MethodInfo method =type.GetMethod(args[1],BindingFlags.Instance|BindingFlags.Public|BindingFlags.IgnoreCase);
36 object returnObj=method.GetParameters() != null?method.Invoke(obj,cmd.Substring(args[0].Length + args[1].Length + 2).Split(‘,’))
37 :method.Invoke(obj, null);
38
39 //如国返回String类型或值类型则输出到页面
40 if (method.ReturnType == typeof(string) ||obj is ValueType)
41 context.Response.Write(returnObj.ToString());
42 }
43 }
44
45 #endregion
46 }
47 }
东方网新,为您提供专业的网站建设,软件开发,网络营销SEO,网络推广服务,代理国外主机空间,域名注册,服务热线:(+86)18608275575,电子邮件:master#atnet.cc;欢迎您访问东方网新网站:www.atnet.cc

然后我们创建1个WebHandler将其Class设为”HuiShi.Web.ExecuteHandler”,再在 ExecuteHandler命名空间下创建几个类,并用[WebExecute]特性修饰,这样我们只需要加代码而不用加文件就可以完成操作了!是不是 省了很多功夫,将使用WebHandler请求的类放到1个文件中集中管理,不是方便了代码组织管理吗?

想想上面的实现,没什么错误,但如果我们要将WebHandler封装成一个动态链接库,引用到其他项目的话呢?

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(2)

mikel阅读(888)

[转载]更灵活,更易维护的WebHandler之通用webHandler编码方案(2) – 刘铭.net-OPS.cc – 博客园.

上一篇:更灵活,更易维护的WebHandler之通用webHandler编码方案(1) 中介绍了在同一个程序集中使用webHandler执行类的方法,

但在多数情况下,我们会将WebHandler封装进一个单独的动态链接库,我们需要将引用WebHandler DLL的程序集或程序集中的任意一个类的Type做为参数传递给WebHandler,

这样就可以在WebHandler中利用反射调用引用WebHandler类库的程序集中的代码!

实现代码如下:

01 /* *
02 * name     : ExecuteHandler.cs
03 * author   : newmin
04 * date     : 09/29 2010
05 * note     : 用来处理请求,请求的URI参数如:Exc.ashx?cmd=IP,GetIP,127.0.0.1
06 *
07 * 要执行操作的类必需要程序集名称命名空间下:
08 * 如要执行AtNet.Security下的User类,则User类的命名空间为:HuiShi.Security.User
09 * 调用方式**.ashx?cmd=User,GetScore,newmin
10 *
11 * */
12 namespace AtNet.Web
13 {
14 using System;
15 using System.Web;
16 using System.Reflection;
17 using System.Collections.Generic;
18
19 public abstract class ExecuteHandler : IHttpHandler
20 {
21 //绑定类型用于获取程序集,只能在子类的静态构造函数中赋值
22 protected static Type _type;
23 #region IHttpHandler 成员
24 public bool IsReusable{ get; set; }
25
26 public void ProcessRequest(HttpContext context)
27 {
28 string cmd=context.Request["cmd"].Replace("+"," "); //将空格做为+号替换
29
30 string[] args = cmd.Split(',');
31 if (args.Length > 2)
32 {
33 //获取执行当前代码的程序集并创建实例
34 Assembly ass = Assembly.GetAssembly(_type);
35 object obj = ass.CreateInstance(_type.Namespace+"."+args[0], true);
36
37 //获取实例类型
38 Type type=obj.GetType();
39
40 //未添加WebExecuteAttribute特性的类将不被执行
41 object[] attrs= type.GetCustomAttributes(typeof(WebExecuteAttribute), false);
42 WebExecuteAttribute attr =attrs.Length>0?attrs[0] as WebExecuteAttribute:null;
43 if (attr == null) { context.Response.Write("此模块不允许被执行!"); return; }
44
45 //获取方法并执行
46 MethodInfo method =type.GetMethod(args[1],BindingFlags.Instance|BindingFlags.Public|BindingFlags.IgnoreCase);
47 object returnObj=method.GetParameters() != null?method.Invoke(obj,cmd.Substring(args[0].Length + args[1].Length + 2).Split(','))
48 :method.Invoke(obj, null);
49
50 //如国返回String类型或值类型则输出到页面
51 if (method.ReturnType == typeof(string) ||obj is ValueType)
52 context.Response.Write(returnObj.ToString());
53 }
54 }
55
56 #endregion
57 }
58 }

我们需在继承ExecuteHandler的类的静态构造函数中对_type赋值:

01 namespace AtNet.Web.Tools
02 {
03 using System;
04 using System.Reflection;
05
06 public class WebHandler:AtNet.Web.ExecuteHandler
07 {
08 static WebHandler()
09 {
10 _type = typeof(WebHandler);
11 }
12 }
13 }

这样我们就能在将ExecuteHandler分离出来,被别的项目所引用

[转载]Lucene.Net:构造搜索表达式简化搜索

mikel阅读(1039)

[转载]Lucene.Net:构造搜索表达式简化搜索 – 努力,天赋,笑容,自信 – 博客园.

我们知道利用Lucene.Net的不同的Query(常见如BooleanQuery,RangeQuery等等),可以有针对性地进行各种不同 类型的搜索。利用QueryParser(或MultiFieldQueryParser),配合构造好的搜索关键字(搜索表达式),也可以实现不同类型 的搜索。本文重点就是简单介绍一下搜索表达式和不同类型的Query之间的简单对比。本文最后的demo,QueryApp工程下有文章里贴出的大部分示 例代码,代码自己会说话,有时候它可能更好地表达了文章作者的思路。您可以下载对照着本文进行阅读。

一、与或非

1、与

举例:搜索contents既包含“jeffreyzhao”,又有“ 老赵”的记录:

1 public static void NormalQueryParserTest(Analyzer analyzer, string field, string keyword)
2 {
3 QueryParser parser = new QueryParser(Version.LUCENE_29, field, analyzer);
4 Query query = parser.Parse(keyword);
5 ShowQueryExpression(analyzer, query, keyword);
6 SearchToShow(query);
7 Console.WriteLine();
8 }

调用的时候,我们构造一个搜索关键词“+jeffreyzhao +老赵”:

1 string field = "contents";//搜索的对应字段
2 keyword = "+jeffreyzhao +老赵";
3 LuceneSearch.NormalQueryParserTest(analyzer, field, keyword);//+contents:jeffreyzhao +contents:"老 赵"

搜索结果中我们可以看到,通过加号(+)可以表达与(AND)的关系(+contents:jeffreyzhao +contents:”老 赵” )。

特点:不同关键字越多,匹配的结果可能越少。

2、或

输入多个关键字,任何包含其中一个关键字的记录都被搜索出来:

1 string keyword = "jeffreyzhao 老赵";//搜索输入关键词
2 string field = "contents";//搜索的对应字段
3 LuceneSearch.NormalQueryParserTest(analyzer, field, keyword); //contents:jeffreyzhao contents:"老 赵"

特点:不同关键字越多,匹配的结果可能越多。

3、非(!)

1 keyword = "+jeffreyzhao -老赵";
2 LuceneSearch.NormalQueryParserTest(analyzer, field, keyword);//+contents:jeffreyzhao -contents:"老 赵"
3
4 keyword = "+jeffreyzhao !老赵";
5 LuceneSearch.NormalQueryParserTest(analyzer, field, keyword);//+contents:jeffreyzhao -contents:"老 赵"

上面的两种写法,转换成表达式都是+contents:jeffreyzhao -contents:”老 赵” 。

根据我们的测试结果,与或非的关系可以总结如下:

a & b  =>   +a +b
a || b  =>   a    b
a  !b   =>   +a  -b

这种与或非的关系,我们还可以通过BooleanQuery表达同样的搜索:

01 public static void BooleanQueryTest(Analyzer analyzer, string field, string keyword, BooleanClause.Occur[] flags)
02 {
03 Console.WriteLine("====BooleanQuery====");
04 string[] arrKeywords = keyword.Trim().Split(new char[] { ' ', ',', ',', '、' }, StringSplitOptions.RemoveEmptyEntries);
05 QueryParser parser = new QueryParser(Version.LUCENE_29, field, analyzer);
06 BooleanQuery bq = new BooleanQuery();
07 int counter = 0;
08 foreach (string item in arrKeywords)
09 {
10 Query query = parser.Parse(item);
11 bq.Add(query, flags[counter]);
12 counter++;
13 }
14 ShowQueryExpression(analyzer, bq, keyword);
15 SearchToShow(bq);
16 Console.WriteLine();
17 }

其中BooleanClause.Occur(MUST:+  MUST_NOT:-   SHOULD:无符号)的选择至关重要:

01 string field = "contents";//搜索的对应字段
02 IList<Analyzer> listAnalyzer =LuceneAnalyzer. BuildAnalyzers();
03 BooleanClause.Occur[] occurs = new BooleanClause.Occur[] { BooleanClause.Occur.MUST, BooleanClause.Occur.MUST };
04 foreach (Analyzer analyzer in listAnalyzer)
05 {
06
07 //NormalQueryTest(analyzer);
08 //LuceneSearch.NormalQueryParserTest(analyzer, field, keyword);//直接通过QueryParser配合构造好的查询表达式搜索
09
10 //LuceneSearch.TermQueryTest(analyzer, field, "高手");//contents:高手
11
12 LuceneSearch.BooleanQueryTest(analyzer, field, "jeffreyzhao 老赵", occurs);//+contents:jeffreyzhao +contents:"老 赵"
13
14 //LuceneSearch.RangeQueryTest(analyzer, rangeField, start, end); // createdate:[20101010 TO 20110101]  createdate:[20101010 TO 20110101}
15
16 //LuceneSearch.PrefixQueryTest(analyzer, field, "hell"); // contents:hell*  (可以找到hello world那一项)
17
18 //LuceneSearch.WildcardQueryTest(analyzer, field, "高手"); //contents:高手
19
20 //LuceneSearch.FuzzyQueryTest(analyzer, field, "牛"); //contents:牛~0.5
21
22 //LuceneSearch.PhraseQueryTest(analyzer, field, "hello world", 1); //contents:"hello world"~1
23
24 //LuceneSearch.MulFieldsSearchTest(analyzer, fieldArr, "博  园", occurs); //+(contents:博 contents:园) +(title:博 title:园)
25 }

二、范围

01 string rangeField = "createdate";//范围搜索对应字段
02 string start = "20101010";
03 string end = "20110101";
04 IList<Analyzer> listAnalyzer =LuceneAnalyzer. BuildAnalyzers();
05 foreach (Analyzer analyzer in listAnalyzer)
06 {
07
08 LuceneSearch.RangeQueryTest(analyzer, rangeField, start, end); // createdate:[20101010 TO 20110101]  createdate:[20101010 TO 20110101}
09
10 }

同样道理,RangeQuery(或者TermRangeQuery)也可以实现范围搜索。

三、多字段组合搜索

搜索时,对两个或多个字段进行匹配的时候,可以用下面的方法:

01 public static void MulFieldsSearchTest(Analyzer analyzer, string[] fields, string keyword, BooleanClause.Occur[] flags)
02 {
03 Console.WriteLine("====MultiFieldQueryParser====");
04 MultiFieldQueryParser parser = new MultiFieldQueryParser(Version.LUCENE_29, fields, analyzer);
05 //Query query = parser.Parse(keyword);
06 Query query = MultiFieldQueryParser.Parse(Version.LUCENE_29, keyword, fields, flags, analyzer);
07 ShowQueryExpression(analyzer, query, keyword);
08 SearchToShow(query);
09 Console.WriteLine();
10 }

简单调用如下:

1 string[] fieldArr = new string[] { field, "title" };//两个字段
2 IList<Analyzer> listAnalyzer =LuceneAnalyzer. BuildAnalyzers();
3 foreach (Analyzer analyzer in listAnalyzer)
4 {
5 LuceneSearch.MulFieldsSearchTest(analyzer, fieldArr, "博  园", occurs); //+(contents:博 contents:园) +(title:博 title:园)
6 }

如果我们把搜索关键字改为“博 -园”,则表达式就是“+(contents:博 -contents:园) +(title:博 -title:园)”,这也符合单个字段搜索。

注意:如你所知,与或非和范围不是搜索关系的全部。实际上,通过Lucene,你可以根据 +-!():^[]{}~*? 这几种符号,合理构造出表达真实意图的复杂表达式来代替不同类型的Query。我在示例代码中做了几个针对StandardAnalyzer的简单尝试,测试结果符合预期。

我在参考网上不少文章的时候,发现很多提到的问题都没有重现,再看他们的lucene的版本都低于2.0,我大胆猜测Lucene.Net的类库已经改进了不少,一开始还以为自己的测试不到位,囧。

四、分词效果

Analyzer选择不同,搜索结果也不同,尤其是对于中文。用下面的函数可以测试分词效果:

01 /// <summary>
02 /// 测试不同的Analyzer分词效果
03 /// </summary>
04 /// <param name="listAnalyzer"></param>
05 /// <param name="input"></param>
06 public static void TestAnalyzer(IList<Analyzer> listAnalyzer, string input)
07 {
08 foreach (Analyzer analyzer in listAnalyzer)
09 {
10 Console.WriteLine(string.Format("{0}:", analyzer.ToString()));
11
12 using (TextReader reader = new StringReader(input))
13 {
14 TokenStream stream = analyzer.ReusableTokenStream(string.Empty, reader);
15 Lucene.Net.Analysis.Token token = null;
16 while ((token = stream.Next()) != null)
17 {
18 Console.WriteLine(token.TermText());
19 }
20 }
21
22 Console.WriteLine();
23 }
24 }

不同的Analyzer,分词效果可以总结如下:

StandardAnalyzer       对中文单字拆分;

WhitespaceAnalyzer  按空格拆分,对中文的支持不好;

KeywordAnalyzer       输入什么,分词就是什么;

SimpleAnalyzer           按标点和空格拆分,对中文的支持不好

StopAnalyzer               和SimpleAnalyzer类似;

选来选去,StandardAnalyzer 的效果还是很不错的,一般的应用差不多就够用了。 您可以使用不同的Analyzer,然后对比它们的搜索表达式并找出它们的不同之处。

demo下载:LuceneNetApp

[转载]ASP.NET MVC中的扩展点(五)方法选择器

mikel阅读(976)

[转载]MVC中的扩展点(五)方法选择器 – xfrog – 博客园.

前一篇中我们介绍了过滤器,通过方法和结果过滤器我们可以在MVC执行方法及结果的前后注入自己的功能,通过授权过滤器可以执行一些权限检查,阻止无权用 户调用方法,通过异常过滤器处理方法执行过程中产生的异常。那么在执行方法之前,MVC又是如何确定使用何种控制器及其方法的呢?

我们已经知道,MVC使用DefaultControllerFactory控制器工厂来实例化控制器,其大致过程如下:

1、默认Route类的GetRouteData方法将按我们设定的Url规则解析当前请求的Url,并将Url规则中的给个参数存入RouteData.Values集合中。我们知道Mvc添加了一个默认的Route项:

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
 );

.codearea { color: black; background-color: white; line-height: 18px; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,”BitStream Vera Sans Mono”,courier,monospace,serif; }.codearea pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap pre { white-space: pre-wrap; word-wrap: break-word; }.codearea pre.alt { background-color: rgb(247, 247, 255) ! important; }.codearea .lnum { color: rgb(79, 129, 189); line-height: 18px; }

按以上规则,如果我们请求的Url为:

http://localhost/News/GetNewsList

则对应的RouteData.Values[“controller”] = “News”;  RouteData.Values[“action”] = “NewsList”

2、DefaultControllerFactory根据Route.Values[“controller”]确定实际的控制器类型,并实例化,如上例控制器工厂知道应实例化的控制器类型为NewsController。

3、通过控制器工厂返回的Controller对象的 Execute方法,控制器通过一个实现了IActionInvoker接口的类(默认为ControllerActionInvoker类)使用 RouteData.Values[“action”]值,确定具体运行控制器中的那一个方法。

4、执行控制器中的方法生成ActionResult

5、执行ActionResult.ExecuteActionResult生成最终应答内容。

在4、5步骤中涉及到我们上一章中介绍的过滤器,而方法选择器是在第3步骤中使用的,ControllerActionInvoker类中使用ActionMethodSelector类来获取与路由信息匹配的方法,具体执行过程如下图所示:

SelectorActivity

图中红色终点表示异常。ActionMethodSelector首先从控制器中非静态方法中获取方法名称等于 RouteData.Values[“action”]或通过ActionName特性指定的名称等于 RouteData.Values[“action”]的方法列表,其次依次调用方法列表中的每个方法上的选择器,去掉选择器返回为false的部分,如 果最终由一个方法匹配则使用这个方法,如果没有方法匹配,则再检查方法列表中没有选择器的方法,如果存在一个,选中它,如果没有,则直接调用控制器的 HandleUnknownAction方法,Controller中此方法默认返回一个404的HTTP错误。

下面我们来看MVC中实现的默认选择器类型:

SelectorClass

ActionNameAttribute用于声明方法的别名,通常情况下使用ActionName将控制器中不同的方法映射为相同的控制器方法(相同的 Url访问不同的方法)。它从抽象类ActionNameSelectorAttribute继承,你也可以从此类中继承实现自己的ActionName 特性(不过似乎用处不大)。

ActionMethodSelectorAttribute抽象类是一些列选择器的基类,ActionMethodSelector选择方法时,会调用 IsValidForRequest方法来检查当前方法是否有效。MVC实现了几个默认的选择器:HttpGet、HttpPost、 HttpDelete、HttpPut以及AcceptVerbs用于检查当前请求的方式(匹配GET方法、POST方法等,AcceptVerbs用于 匹配多个方法),事实上HttpGet等选择器是对AcceptVerbs的封装。另外一个选择器:NonAction表示当前方法不对外部请求公开(它 的IsValidForRequest始终返回false)。如果我们需要实现自己的选择逻辑,则应从 ActionMethodSelectorAttribute类继承。

以下示例实现一个选择器,将根据浏览器类型将相同的Url映射到不同的控制器方法:

1、创建一个空的MVC项目

2、实现BrowseSelectorAttribute

显示行号 复制代码 BrowseSelectorAttribute
  1. public class BrowseSelectorAttribute : ActionMethodSelectorAttribute
    
  2. {
    
  3.     private string _userAgent = String.Empty;
    
  4.     public BrowseSelectorAttribute(string userAgent)
    
  5.     {
    
  6.         _userAgent = userAgent;
    
  7.     }
    
  8.     public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    
  9.     {
    
  10.         return controllerContext.HttpContext.Request.UserAgent.Contains(_userAgent);
    
  11.     }
    
  12. }
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }3、创建HomeController控制器

显示行号 复制代码 HomeController
  1. public class HomeController : Controller
    
  2. {
    
  3.     [ActionName("Index")]
    
  4.     [BrowseSelector("MSIE")]
    
  5.     public ActionResult IEIndex()
    
  6.     {
    
  7.         return Content("通过IE浏览器访问");
    
  8.     }
    
  9.     [ActionName("Index")]
    
  10.     [BrowseSelector("Chrome")]
    
  11.     public ActionResult ChromeIndex()
    
  12.     {
    
  13.         return Content("通过Chrome浏览器访问");
    
  14.     }
    
  15.     [ActionName("Index")]
    
  16.     public ActionResult OtherIndex()
    
  17.     {
    
  18.         return Content("通过其他浏览器访问");
    
  19.     }
    
  20. }
    

.src_container { background-color: rgb(231, 229, 220); width: 99%; overflow: hidden; margin: 12px 0pt ! important; padding: 0px 3px 3px 0px; }.src_container .titlebar { background-color: rgb(212, 223, 255); border-width: 1px 1px 0pt; border-style: solid solid none; border-color: rgb(79, 129, 189) rgb(79, 129, 189) -moz-use-text-color; padding: 3px 24px; margin: 0pt; width: auto; line-height: 120%; overflow: hidden; text-align: left; font-size: 12px; }.src_container .toolbar { display: inline; font-weight: normal; font-size: 100%; float: right; color: rgb(0, 0, 255); text-align: left; overflow: hidden; }.toolbar span.button { display: inline; font-weight: normal; font-size: 100%; color: rgb(0, 0, 255); text-align: left; overflow: hidden; cursor: pointer; }.src_container div.clientarea { background-color: white; border: 1px solid rgb(79, 129, 189); margin: 0pt; width: auto ! important; height: auto; overflow: auto; text-align: left; font-size: 12px; font-family: “Courier New”,”Consolas”,”Fixedsys”,courier,monospace,serif; }.src_container ol.mainarea { padding: 0pt 0pt 0pt 52px; margin: 0pt; background-color: rgb(247, 247, 255) ! important; }.number_show { padding-left: 52px ! important; list-style: decimal outside none ! important; }.number_show li { list-style: decimal outside none ! important; border-left: 1px dotted rgb(79, 129, 189); }.number_hide { padding-left: 0px ! important; list-style-type: none ! important; }.number_hide li { list-style-type: none ! important; border-left: 0px none; }ol.mainarea li { display: list-item ! important; font-size: 12px ! important; margin: 0pt ! important; line-height: 18px ! important; padding: 0pt 0pt 0pt 0px ! important; background-color: rgb(247, 247, 255) ! important; color: rgb(79, 129, 189); }ol.mainarea li pre { color: black; line-height: 18px; padding: 0pt 0pt 0pt 12px ! important; margin: 0em; background-color: rgb(255, 255, 255) ! important; }.linewrap ol.mainarea li pre { white-space: pre-wrap; word-wrap: break-word; }ol.mainarea li pre.alt { background-color: rgb(247, 247, 255) ! important; }

最后,选择器的功能似乎与授权过滤器类似:都可以”过滤”掉控制器方法,但是他们本质上是不同的:执行授权过滤器时,MVC已经确定调用哪个控制器方法, 而选择器是在MVC选择控制器方法时得一组过滤条件。如果通过选择器过滤后没有匹配方法,默认下会返回404错误,如果通过授权过滤器终止执行某个方法, 则返回的是你在通过授权过滤器上下文参数中指定的Result。

源代码下载

[转载]android 游戏导引(1. 建立 OpenGL 项目)

mikel阅读(1054)

[转载]android 游戏导引(1. 建立 OpenGL 项目) – 圣斗士 – 博客园.

Android 游戏导引(1. 建立 OpenGL 项目)

1 搭建环境

我的环境是 mac, 鉴于 windows 下搭建的教程网上很多,大家可以 google 之。说一下 mac 下的环境搭建过程。

  1. 下载 mac 版本的 Android SDK。天朝墙很坚固,贴下 2.3 下载地址,可以用超强盗链功能的迅雷下载。
    Platform Package Size MD5 Checksum
    Mac OS X (intel) android-sdk_r08-mac_86.zip 28797617 bytes d2e392c4e4680cbf2dfd6dbf82b662c7
    Linux (i386) android-sdk_r08-linux_86.tgz 26817291 bytes 3b626645b223d137d27beefbda0c94bc
  2. 解压文件。点击 tool 目录下的 android 文件。选择要下载的相应版本的 SDK, 文档,工具等。
  3. android 要求 jdk 版本大于 1.5, mac os x上预装的是 1.6 的版本。(java -version查看)。所以不必再下 jdk 了(想下官网也没提供mac版本)。
  4. 下载 Eclipse, 版本是 for Java Developers 的就可以。解压到某个文件夹下,直接运行其中的eclipse 就使用。
  5. 安装 adt。 Eclipse 的 Help菜单下的 Install new Software…. 点击 add 按钮, 在弹出的对话框 Location 中,输入 http://dl-ssl.google.com/android/eclipse/, OK, 省略。。。
  6. 配置 Eclipse 的android 环境。重启 Eclipse, 点击Eclipse 菜单下的 Preferences, 打开设置界面。找到android 项, 设置好 android sdk 目录,点 apply, 会显示你所有的 sdk 版本。OK。
  7. 建立一个 avd。 打开 Eclipse 的 Windows 菜单下的 “Android SDK and AVD”,创建好一个 avd。就正式配置成功了。

2 创建一个 android 项目

“File” -> “New”-> “Project”: 选择 android 工程:

设置好项目的信息和sdk版本:

好了一个项目就创建完了。

3 建立 OpenGL 程序框架

默认的,建立的程序中,一个 activity 的源码如下:

public class GlGame extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}

OpenGL 有自己的Surface: GLSurfaceView, 它内部提供了一个 Renderer 接口,我们所要做的就是注册一个自己的 Renderer。好了,先看我们的 activity:

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.opengl.GLSurfaceView.Renderer;
import android.os.Bundle;
public class GlGame extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.main);
Renderer render = new MyRenderer();//要实现的 Renderer
GLSurfaceView glView = new GLSurfaceView(this);
glView.setRenderer(render);
setContentView(glView);
}
}

Renderer 必须要实现3个抽象方法:

  • public void onDrawFrame(GL10 gl) 绘制
  • public void onSurfaceChanged(GL10 gl, int width, int height) 窗口大小改变
  • public void onSurfaceCreated(GL10 gl, EGLConfig config) 窗口建立

添加类 MyRenderer:

01 import javax.microedition.khronos.egl.EGLConfig;
02 import javax.microedition.khronos.opengles.GL10;
03
04 import android.opengl.GLSurfaceView.Renderer;
05
06 public class MyRenderer implements Renderer{
07
08 public void onDrawFrame(GL10 gl) {
09 gl.glClearColor(1, 0, 0, 0);
10 // 清除屏幕和深度缓存
11 gl.glClear(GL10.GL_COLOR_BUFFER_BIT) | GL10.GL_DEPTH_BUFFER_BIT);
12 }
13
14 public void onSurfaceChanged(GL10 gl, int width, int height) {
15 // 设置 OpenGL 场景的大小
16 gl.glViewport(0, 0, width, height);
17 }
18
19 public void onSurfaceCreated(GL10 gl, EGLConfig config) {
20 // TODO Auto-generated method stub
21
22 }
23
24 }

好了一个 OpenGL 框架就搭好了。接下来我们就进行可爱地屏幕绘制相关地东西了。下次再说吧。

[转载]VS2010设置断点无效的解决方法

mikel阅读(1210)

[转载]VS2010设置断点无效的解决方法 – giser2007 – 博客园.

当前不会命中断点,还没有为该文档加载任何符号”这个提示可能很多人都遇到过,首先我列几条网上常见的解决方案。

1、生成方式是Realse不是Debug

2、调试时到“附加到进程”菜单里看有没有“aspnet_wp.exe”的进程,如果没有,添加。

3、控件的事件丢失。

4、右键解决方案的属性里,看生成项里的“生成调试信息”那里是不是FALSE,如果是,改成TRUE。

5、想要调试的代码行根本不能调试。

可是我不属于其中任何一种。。但以上总结的5种的确也是原因,暂且写上。

后来突然灵光乍现,会不会是浏览器的问题,很多朋友可能默认浏览器不是IE,以前用VS2005时,都是会用IE打开页面,而到了VS2010,会 用电脑设置的默认浏览器打开,当然你把电脑的默认浏览器换成IE就可以解决,不过这样总感觉有点不爽,不过你不用担心,有解决方案。我现在是用 silverlight做开发,所以就以silverlight为例。

右键点击sampleTestPage.aspx(sample是解决方案名称)——浏览方式——把IE设置为默认——OK

[转载]android 游戏导引(2. 游戏的基础设置)

mikel阅读(1028)

[转载]android 游戏导引(2. 游戏的基础设置) – 圣斗士 – 博客园.

Android 游戏导引(2. 游戏的基础设置)

上一节已经学习了一个基本的 OpenGL 框架了,今天这一节就进一步设置一下 2D 游戏相关的东西了。对 2D 游戏的喜爱甚于 3D。 相信大多数人也是吧。

1 游戏全屏显示

2行代码搞定,一个让应用去掉自己的标题栏,一个设置全屏,放在应用的创建函数 OnCreate 中:

public class GlGame extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams. FLAG_FULLSCREEN ,
WindowManager.LayoutParams. FLAG_FULLSCREEN);
// ... 其他略
}
}

2 设置 OpenGL 的 2D 环境

我们先要设计好要建立的世界定位方式,就是坐标系,一般的 opengl 程序是标准的笛卡尔坐标系,即左下角为原点,x横向右延伸,y纵向上延伸。像著名的 cocos2d 引擎就是此种方式。我比较偏好另一套就是左上角为原点的描述方式,所以采用了此套坐标系:

GLSurfaceView 的 Renderer,给出了三个接口:创建时,大小改变时,绘制。我们在三个函数中采取的操作如下:

  • 创建时, onSurfaceCreated, 进行 OpenGL 的基本设置,如阴影平滑,深度测试啊神马的。
  • 大小改变时,onSurfaceChanged, 进行投影,视口等设置。
  • 绘制,onDrawFrame, 我们后续的游戏绘制主要在这个函数了。

2.1 onSurfaceCreated

不多说,都是基本设置。

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 告诉系统对透视进行修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
// 背景黑色
gl.glClearColor(0, 0, 0, 1);
// 启用阴影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 设置深度缓存
gl.glClearDepthf(1.0f);
// 启用深度测试
gl.glEnable(GL10.GL_DEPTH_TEST);
// 所做深度测试的类型
gl.glDepthFunc(GL10.GL_LEQUAL);
}

2.2 onSurfaceChanged

public void onSurfaceChanged(GL10 gl, int width, int height) {
// 设置 OpenGL 场景的大小
gl.glViewport(0, 0, width, height);
// 设置投影矩阵
gl.glMatrixMode(GL10.GL_PROJECTION);
// 重置投影矩阵
gl.glLoadIdentity();
// 设置视口的大小
// gl.glOrthof(0, width, height, 0, -1000, 1000);
GLU.gluOrtho2D(gl, 0, width, height, 0);
// 重置模型矩阵
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
}

代码中先用 glViewPort 设定了场景的大小,我们所有的opengl世界都被投射到这个场景中,在这里,我们将场景的大小设置为窗口 Surface 的大小。

继而设置了投影矩阵,投影矩阵定义了 opengl 世界怎样反应在你的场景中,在 OpenGL 中又两种投影方式: 透视和正交。透视比较接近我们现实的方式了,你的眼睛发出的光形成一个夹角,离你的眼睛越近,东西越大,范围越小;反之离眼睛越远,东西越小,视野越开 阔。因此多用于 3D 中。 而正交却是世界中的物体按照平行的光线投射到一张纸上(你的画布),仿佛被压缩在上面,无论这个物体在世界中多远,投射结果还是原来的大小, 2d 游戏多用此种投影。

设置透视投影有 glFrustum 和 glu 库的 gluPerspective, 都可以设置上面透视投影中的角度,远近等参数。还可以 gluLookAt 来设置眼睛(相机)的位置。

设置正交投影有 glOrtho 和 glu 库的 gluOrth2D :

glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
gluOrth2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top);

glu版本的y轴参数不用我们设置了,因为不会用到。由于我们的坐标系以左上角为原点,所以 left 和 top 参数为 0。

glMatrixMode() 函数指定了其下面的代码操作的是何种矩阵。 我们这里用到两类矩阵变换:投影变换和模型视图变换。投影变换中我们更改了世界空间的裁切范围,在模型视图变换中,我们可以移动和旋转世界中的物体,所以 我们在绘制的时候就是在模型视图矩阵变换中。 glLoadIdentity() 用于重置矩阵,清除上次的残留信息。

代码最后设定为模型视图变换,便于我们在绘制函数中移动和变换物体模型了。

2.3 onDrawFrame

先说明一下 GLSurfaceView 的 Renderer 绘制是在独立的线程中完成的,这个函数被不断的循环调用。

前面已经设置为模型视图矩阵了,每次 onDrawFrame 的时候,我们都要 glLoadIdentity 重置一次,清除上次绘制造成的残留信息。

public void onDrawFrame(GL10 gl) {
// 清除屏幕和深度缓存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 重置模型矩阵
gl.glLoadIdentity();
//... 要添加的具体绘制代码
}

3 三角形-测试

好了,上面已经设置好了,我们先来个简单的测试吧,在你的窗口中绘制一个红色三角形。先定义好三角形的三个角度,左上角为 (60,200), 右上角为 (180, 200), 下角为 (120,300)。

01 private FloatBuffer triggerBuffer = FloatBuffer.wrap(new float[]{
02 60,200, // 左上角
03 180, 200, // 右上角
04 120,300, // 下顶角
05 });
06
07 public void onDrawFrame(GL10 gl) {
08 // 清除屏幕和深度缓存
09 gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
10 // 重置模型矩阵
11 gl.glLoadIdentity();
12
13
14 gl.glPushMatrix();
15 gl.glColor4f(1, 0, 0, 0);
16 // 允许设置顶点
17 gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
18 gl.glVertexPointer(2, GL10.GL_FLOAT, 0, triggerBuffer);
19 gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
20 // 取消设置顶点
21 gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
22 gl.glPopMatrix();
23 }

主要代码包围在了 glPushMatrix() 和 glPopMatrix() 中,OpenGL内部维护了各种矩阵栈,栈的操作就是 push 和 pop 了。这里我们的操作是在模型视图矩阵变换中进行的,所以操作的是模型视图栈。之所以压栈,我们不想绘制三角形的矩阵信息污染到外层的矩阵中,比如颜色设置 等。所以大家在绘制一个单位体的时候尽量使用 push 和 pop 操作。

先用 glColor4f 设置绘制颜色为红色。opengles 中少了 glBegin, glEnd 类标准函数,采用了数组顶点来设坐标方式,主要还是性能考虑吧。默认是关掉这个选项的,所以先开启,不用了再关闭: glEnableClientState(GL10.GLVERTEXARRAY), glDisableClientState(GL10.GLVERTEXARRAY).

指定数组顶点用 glVertexPointer, 指定完了就可以用 glDrawArray() 来将指定的数组中的顶点绘制出来了。这里有必要罗嗦一下这两个函数了,因为这两个函数用到的太多了。先看第一个:

void glVertexPointer (int size, int type, int stride, Buffer pointer)

参数:

size
每个顶点有几个数值描述。必须取值2,3,4之一。初始值是 4.
type
数组中每个顶点坐标的类型。取值:GLBYTE, GLSHORT, GLFIXED, GLFLOAT。初始值为 GLFLOAT。
stride
数组中每个顶点间的间隔,步长(字节位移)。取值若为 0 表示数组是连续的。初始值为 0。
pointer
就是你的数组了,存储着每个顶点的坐标值。初始值为 0。

注意了, type 中告诉 opengl 你的数组类型。 GLBYTE, GLSHORT, GLFLOAT 对应 byte[], short[], float[]. GLFIXED 对应 int[]. 有一个特别的地方, GLFIXED 描述的时候,大家的点坐标单位是 0x10000, 比如一个点是 (60, 120), 用 GLFIXED 的时候,需要设置为 (60 * 0x10000, 120 * 0x10000), 所以经常看到 int one = 0x10000 的编程语句, 这个数值就是这么来的。

再来看 glDrawArray:

void glDrawArrays (int mode, int first, int count);

参数:

mode
指定你要绘制何种图元, opengl 中的图元就这几个: GLPOINTS, GLLINESTRIP, GLLINELOOP, GLLINES, GLTRIANGLESTRIP, GLTRIANGLEFAN, GLTRIANGLES.
first
在已制定的数组中的开始位置(索引位置)
count
点的绘制次数, 比如我们绘制一个三角形,就是绘制三个顶点,即此参数为 3。

这两个函数就介绍这么多了,足以应付这个程序了。有问题可以查官方函数文档: http://www.khronos.org/opengles/sdk/1.1/docs/man/

好了,代码就介绍完了。一个三角形大家应该会绘制了吧,大家可以试试其他的图元,点,线,四边形,多边形等等。

学习愉快。

[转载]android 游戏导引(3. 图形引擎之模型管理)

mikel阅读(951)

[转载]android 游戏导引(3. 图形引擎之模型管理) – 圣斗士 – 博客园.

Android 游戏导引(3. 图形引擎之模型管理)

上一节中,我们构建了一个自己的场景世界。可以在内部绘制一些基本图元了。本来这一节要说说贴图的,想想还是休息下,放个小插曲,思考下模型的管 理,游戏引擎相关的东西。这些东西跟 cocos2d 很像,可能是 iphone 下常用 cocos2d 的缘故吧, 反正成熟且成功的东西,我们拿来用就行了。

源码下载: 点我吧

1 面向对象吧

基于教程到这里的进度,我们要会议几个图元模型的话,就要显式的在 onDrawFrame 中绘制。基于面向对象的思想,我们知道我们绘制的模型仅仅是一个渲染单位而已,并且我们在 onDrawFrame 的操作只是一个opengl 访问。 因此基于接口,我们的一个渲染模型类就诞生了。

2 模型父子链:树

你也许会说,上面要渲染的模型太多的时候太散乱了。想到这里,说明你还是一个合格的程序员,有着对完美的执着。与其手动的管理,不如让程序自己管 理。大家想想,如果是一个复杂的模型,比如一个人,它是有众多细小的模型构成的,比如脑袋,胳膊,腿等, 而脑袋又有鼻子,耳朵,嘴巴等构成。哈哈,这就是一个树形的结构了,看下结构特征:

  • 一个父节点有0个或多个子节点
  • 一个字节点最多有一个父节点

一个对象的父子关系如下:

现在游戏多采用树形模型管理,而且在 GUI 系统中也大放异彩。有了树形管理,我们可以轻易的将一种类型的鼻子安装到不同人的脑袋上,不用重复发明轮子了。

好了,现在我们的 onDrawFrame 中的形式是这样的了,右边的模型对象是一个封装好的单位,可能内部许多子节点。

3 层式屏幕管理

我们最终是要把模型绘制到屏幕上,我们思考下面问题:

  1. 屏幕上有众多模型需要渲染。比如一个人在草原中散步。概括讲人模型,还有草原,太阳,河流等等。
  2. 屏幕上的模型又可以归为不同的类别。如草原,太阳,河流这些是背景,我们控制的人是前景。

于是,层式管理来了,我们的渲染根结点称为场景 Scene, 分为不同的层 Layer, 在每一层上挂接着具体的模型。看下图就明白了,(注:来自cocos2d-python 文档)

为了向渲染 onDrawFrame 突出接口,Scene 和 Layer 也是一个渲染模型单位。

看看我们添加层式屏幕管理后的效果, 我们将所有要绘制的东西添加到一个场景中,就直接对这个场景节点 glVisit() 就可以了:

每个模型突出一个 glVisit(),这个函数的主要功能是调用自身绘制函数 draw() 然后对各个字节点逐个调用 glVisit().

4 游戏引擎

一个游戏引擎的设计遵循的原则是: 逻辑要和渲染分离,尽量将opengl 最小程度封装在底层,上层使用尽量不要触及底层api,尽量让核心代码原理Android系统的api。组件最小集合应该包含下面几种:

  • 图形引擎,我们上述讨论的就是
  • 事件分派系统,手机应用是基于触摸事件的,所以独立出来(事实上,也是一个调度器)
  • 时间调度器,游戏除了触摸时间还有自身的时间事件,如动画

其他的可能用到的组件有碰撞检测系统,输入系统,寻路算法等等。

游戏引擎的丰富会在以后的教程中逐步增设,今天这一节算是个开头,弄了个简单的图形引擎,也会在接下来随着需求的需要丰富其功能和接口。为了便于从 Android 相关代码中解脱出来,添加一个 GameSystem 单件类:

public class GameSystem {
private static GameSystem instance_ = new GameSystem();
public static GameSystem getInstance()  { return instance_;   }
// 场景
private GlObject runningScene_= null;
private int width = 0; // opengl的场景尺寸
private int height = 0;
public void setWindowSize(int width, int height)
{
this.width = width;
this.height = height;
}
public int getWindowWidth() { return this.width;  }
public int getWindowHeight()    { return this.height; }
// 设定场景
public void setScene(GlObject scene){       runningScene_ = scene;  }
//
public void glVisit(GL10 gl)    {
if (runningScene_ != null)
runningScene_.glVisit(gl);
}
}

我们将其插入到 android 代码的三个地方:

  1. Activity 的 onCreate 方法中,设定WindowSize: setWindowSize. 设定初始场景 setScene
  2. Renderer 的 onDrawFrame 方法中,来访问GameSystem 的游戏场景 glVisit

5 代码实现

在屏幕中除了上面的接口以外,增加的是坐标点,存储的是相对坐标,相对于父节点而言,用于描述模型的位置。这个坐标点不要理解为顶点数组中的顶点坐标。 可以这样理解,你将画笔移动到坐标点处,然后在此处依据顶点数组来绘制。代码较长,省略了一些,可以下载源码。

public class GlObject {
protected GlObject parent = null; // 父节点
protected LinkedList<GlObject> children = new LinkedList<GlObject>();// 字节点
private boolean visible = true; // 可访问(对 gl)
float x = 0;
float y = 0;
// 父子链管理
public void addChild(GlObject obj)  {
children.add(obj);
obj.parent = this;
}
public void removeChild(GlObject obj)   {
obj.parent = null;
children.remove(obj);
}
public void setParent(GlObject p)   {
if (parent != null) parent.removeChild(this);
p.addChild(p);
}
public GlObject getParent() { return parent;  }
// 坐标
float getX()    { return x;   }
float getY()    { return y;   }
void setXY(float x, float y)    {
this.x = x;
this.y = y;
}
// visible
public void setVisible(boolean v)   {       visible = true; }
public boolean getVisible() { return visible; }
// 外部gl访问接口
public void glVisit(GL10 gl)    {
if (!visible) return;
gl.glPushMatrix();
gl.glTranslatef(x, y, 0);
this.draw(gl);
for (GlObject child : children)
child.glVisit(gl);
gl.glPopMatrix();
}
// 绘制自身:子类重写此方法
public void draw(GL10 gl)   {}
////////////////////////////////////////////////////////////////////////////////////////
////  一些常用的图元绘制
// 绘制正方形
public static void drawQuater(GL10 gl, float left, float top, float right,float bottom) {
// 略
}
// 绘制三角形
public static void drawTriangle(GL10 gl, float oneX, float oneY,float twoX, float twoY, float threeX, float threeY) {
// 略
}
// 绘制扇形
public static void drawArc(GL10 gl, float length, float startAngle,float sweepAngle)    {
// 略
}
// 绘制直线
public static void drawLine(GL10 gl, float oneX, float oneY, float twoX,float twoY) {
// 略
}
}

6 绘制一个 android 机器人

代码还是以前的,绘制图元,只不过经过本章的洗礼,代码封装性和扩展性上有了进步。一个机器人有下面的结构组成:

  • 身体
    • 眼睛 * 2
    • 天线
  • 腿 * 2
  • 胳膊 * 2
  1. 设定 GameSystem 的初始游戏场景:
public class GlGame extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
// 。。。。略
// 初始化游戏系统:
// ... 屏幕大小
{
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
GameSystem.getInstance().setWindowSize(dm.widthPixels, dm.heightPixels);
}
// ...设定初始场景
GameSystem.getInstance().setScene(new AndroidScene());
//..... setContentView 代码
}
}

2. 添加一个场景类 AndroidScene 作为我们的画布,我们将会在其上绘制机器人

public class AndroidScene extends GlObject{
AndroidRobot robot = new AndroidRobot();
public AndroidScene(){
super();
// 在屏幕中心绘制
robot.setXY(GameSystem.getInstance().getWindowWidth()/2, GameSystem.getInstance().getWindowHeight()/2);
addChild(robot);
}
}

3. 添加一个机器人渲染模型 AndroidRobot, 代码太长, 折叠之:

好了,本次就唠叨到这里,学习愉快。

[转载]ASP.NET MVC2.0本地化另类解决方案

mikel阅读(959)

[转载]MVC2.0本地化(另类解决方案) – RyanDing – 博客园.

本文是对MVC2.0本地化(另类解决方案)<上>这篇文章内介绍的MVC2.0本地化功能进行加强、细化的结尾篇。如果存在不足的地方,希望您指出。

如何对上篇文章进行加强以及细化呢?主要从以下三点开始。

1、根据用户浏览器自动语言判断,同时也可由用户自定义站点语言。

2、多语言加入,类似resource文件,可以有多个语言资源库。

3、全局本地化,可以本地化非页面内容,比如为台异步到前台的json数据本地化等。

主要步骤如下:

一、根据用户浏览器自动语言判断,同时也可由用户自定义站点语言


这个实现思路为:首选判断存储在客户端的用户“主动”设定的cookie。如果该值为空,则根据用户浏览器自动识别语言。如果不为空则根据用户设定好的 cookie值获取站点语言。那如何根据客户浏览器识别语言,我们要在web.config的<system.web>节点添 加<globalization enableClientBasedCulture=”true” culture=”auto” uiCulture=”auto”/>设置。根据此设置服务器端就就可以使用 System.Threading.Thread.CurrentThread.CurrentCulture识别用户浏览器的语言。贴出global中 部分代码以供参考:

01 protected void Application_BeginRequest(Object sender, EventArgs e)
02 {
03 HttpCookie lang = Request.Cookies["Lang"];
04 if (lang != null)
05 {
06 if (Response.ContentType == "text/html" || Response.ContentType == "application/json")
07 Response.Filter = new LocalizationHandler(Response.Filter, lang.Value);
08 return;
09 }
10 string langFromBrowser = System.Threading.Thread.CurrentThread.CurrentCulture.ToString();
11 string strLang = string.Empty;
12 if (string.Compare("zh-CN", langFromBrowser, true) == 0)
13 {
14 strLang = "SimplifiedChinese";
15 }
16 else if (string.Compare("zh-Hant", langFromBrowser, true) == 0)
17 {
18 strLang = "TraditionalChinese";
19 }
20 else if (langFromBrowser.Contains("en"))
21 {
22 strLang = "English";
23 }
24 else
25 {
26 strLang = "English";
27 }
28
29 if (Response.ContentType == "text/html" || Response.ContentType == "application/json")
30 Response.Filter = new LocalizationHandler(Response.Filter, strLang);
31 }

通过以上代码块,服务端就可以聪明的识别:到底是根据客户端的cookie还是根据用户浏览器语言设定来显示站点语言。

二、多语言加入,类似resource文件,可以有多个语言资源库。


这个扩展就非常简单了,在上篇文章中只有一个XML文件对应于该XML的.net4.0缓存。如果是多语言包,我们只要建立多个XML文件。以及每个XML文件相对应的缓存机制即可。截图如下:

Resources文件下的语言包分为为:英文、简体中文、繁体中文。xml格式请阅 MVC2.0本地化(另类解决方案)<上>

如何获取xml内的翻译文本,上篇文章中写的很清晰了。唯一要注意的是为每个xml文件(语言包)建立独立的缓存机制即可。

三、全局本地化,可以本地化非页面内容,比如为台异步到前台的json数据本地化等


首先看本文实现步骤的第一点中贴出代码第6行,if (Response.ContentType == "text/html" || Response.ContentType == "application/json") 这里控制了json格式的本地化。说白了以后后台的异步到前台的JSON格式的本地化资源,我们也可以写在XML文件中,只要通过Response.Filter 机制就可以本地化,而无需增加额外的本地化代码。

具体实现截图如下:

MVC2.0 JsonResult:

JQuery调用:

最终会将“<=language is applied>”根据不同的国家的用户分别显示成三种语言:

简体:语言已设定。

繁体:語言已經設定。

英文:Language is applied.

四、程序运行截图


五、小结


经过上文的介绍,基本上已完成了本地化另类解决方案。该方案也存在其缺点。但是优点是,可以动态的改变本地化内容。而不需要重新修改源代码,只要修改相应的xml文件内容即可。

希望本篇文章可以给您带来帮助,如有不足之处欢迎指出,谢谢!