本鱼拟成立工作室承接项目开发/软件定制/云设施开发运维/办公设备技术支持等,如您有相关需求,欢迎来询 | ::博客文章推荐::

运行于IIS/MVC平台上的GIT服务器Bonobo Git Server的实践 (附带汉化补丁)

: 汉化/修改作品 木魚 6036℃ 0评论

关于 Bonobo Git Server

之前曾经尝试在Windows平台上搭建一个GIT服务器,无奈又要装SSH又要这个又要那个的,便放在一边了,实在没工夫折腾它。昨天有点烦躁,于是便想折腾点儿什么名堂,这不,就想起折腾它了。

想起它的原因是,之前有看到dudu的《用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器》,看的时候没有在意,这会儿想起来啦,便去下载了回来装上测试,安装其实挺简单,就是还是有点儿问题。

关于安装

安装的过程不用说的,因为 dudu 说得足够明白了。值得一提的是WebDav必须打开,否则在Push的时候会出现“Return Code 22”的错误,其实服务器返回的是这样的一个错误:

图片

嗯没错,PROPFIND这个方法需要WebDAV的支持,所以没打开的时候就会发生这个错误。

当然,Return Code 22 也会有其它原因,后面再说。

值得一提的是,我发现这个程序在IIS Express上也可以正常运行,可见IIS Express足够彪悍。设想一下如果设置Bonobo Git Server的库路径为相对路径,再带上IIS Express,这不就活脱脱一个移动源码库了么。

关于错误

似乎 Bonobo Git Server 设置了“友好的错误信息”显示,因为它在 Global.asax.cs 中出现了如下的代码:

  1. protected void Application_Error(object sender, EventArgs e)
  2. {
  3.     Exception exception = Server.GetLastError();
  4.     Response.Clear();
  5.     HttpException httpException = exception as HttpException;
  6.     RouteData routeData = new RouteData();
  7.     routeData.Values.Add("controller", "Home");
  8.     if (httpException == null)
  9.     {
  10.         routeData.Values.Add("action", "Error");
  11.         if (exception != null)
  12.         {
  13.             Trace.TraceError("Error occured and caught in Global.asax – {0}", exception.ToString());
  14.         }
  15.     }
  16.     else
  17.     {
  18.         switch (httpException.GetHttpCode())
  19.         {
  20.             case 404:
  21.                 routeData.Values.Add("action", "PageNotFound");
  22.                 break;
  23.             case 500:
  24.                 routeData.Values.Add("action", "ServerError");
  25.                 Trace.TraceError("Server Error occured and caught in Global.asax – {0}", exception.ToString());
  26.                 break;
  27.             default:
  28.                 routeData.Values.Add("action", "Error");
  29.                 Trace.TraceError("Error occured and caught in Global.asax – {0}", exception.ToString());
  30.                 break;
  31.         }
  32.     }
  33.     Server.ClearError();
  34.     Response.TrySkipIisCustomErrors = true;
  35.     IController errorController = new HomeController();
  36.     errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
  37. }

简而言之,就是它在服务器处理请求出错的时候,尝试捕获错误的请求,记录日志后重写路由数据到自定义的错误。可惜这个方法并没有判断路径,所以当使用GIT客户端请求的时候它也一律返回HTML格式的错误页面。不过这并不是关键,而是记录下的错误大多是这样的:

w3wp.exe Error: 0 : Server Error occured and caught in Global.asax – System.Web.HttpException (0x80004005): Server cannot set status after HTTP headers have been sent.
   at System.Web.HttpResponse.set_StatusCode(Int32 value)
   at System.Web.HttpResponseWrapper.set_StatusCode(Int32 value)
   at System.Web.Mvc.HttpStatusCodeResult.ExecuteResult(ControllerContext context)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
   at System.Web.Mvc.Controller.ExecuteCore()
   at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
   at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext)
   at System.Web.Mvc.MvcHandler.<>c__DisplayClass6.<>c__DisplayClassb.<BeginProcessRequest>b__5()
   at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.<MakeVoidDelegate>b__0()
   at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
   at System.Web.Mvc.MvcHandler.<>c__DisplayClasse.<EndProcessRequest>b__d()
   at System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f)
   at System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action)
   at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
   at System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

大家应该都看明白了,记录的这个错误根本就不是真正的错误。表面上看的这个错误信息是当响应标头已经发送后,不允许再修改状态码,但实际上是,因为发生了一个错误,导致错误被拦截,拦截之后尝试去更改状态码,可惜这时候又出错了 – -#

所以关于GIT的操作一般一次出错会出现两个错误日志。一个是真正的错误,一个么就是这个 HttpException 了。但是个人感觉,对于开发人员而言,根本不需要什么友好的错误信息,友好的错误信息的存在只会干扰问题的解决。我昨儿遇到问题的时候,就因为这个破烂友好的错误信息的存在,在错误日志里面看到这个HttpException很奇怪,捣鼓了半天才发现这个不是关键,关键在其它地方。所以后来我将这个部分的代码全部取消了,改用Fiddler去抓取提交的请求,很顺利地解决了剩下的问题。

Bonobo Git Server的BUG:修改库路径可能会导致配置文件被破坏

话说上面我屏蔽掉这个友好的错误信息之后才发现原来是这个错误导致的服务器错误:

w3wp.exe Error: 0 : Error occured and caught in Global.asax – System.InvalidOperationException: There is an error in XML document (5, 17). —> System.Xml.XmlException: Data at the root level is invalid. Line 5, position 17.
   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
   at System.Xml.XmlTextReaderImpl.ParseRootLevelWhitespace()
   at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.XmlTextReader.Read()
   at System.Xml.XmlReader.ReadEndElement()
   at System.Xml.Serialization.XmlSerializationReader.ReadEndElement()
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderUserConfiguration.Read2_UserConfiguration(Boolean isNullable, Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderUserConfiguration.Read3_Configuration()
…….

看到服务器返回的错误信息再去看看原来的错误日志,果然有这个错误,只是夹杂在一堆HttpException中太不引人注目了。打开 App_Dataconfig.xml 一看果然文件不对,最后多出了几个字符“ion>”。

为什么多出这么几个字符很让我费解。后来突然想明白了,之前曾经改过GIT库的路径,于是又去做了试验:先将库路径设置为“D:Git”,保存,然后再修改为“D:”,再保存。两次保存的 config.xml 内容如下:

图片

可以看到,库路径变短后文件末尾便多出了那么几个字符。由此可以推测,在保存 config.xml 的时候,它使用了覆写的模式,并且在保存前没有清空源文件,这就导致在新配置内容短于原配置时,原文件最后多出来的字符便充当了“配置杀手”,破坏了配置文件。

看看它的源码确认一下:(UserConfigurationManager.cs)

  1. public static void Save() {
  2.     using (var file = new FileStream(_configPath, FileMode.OpenOrCreate))
  3.     {
  4.         _serializer.Serialize(file, Configuration);
  5.     }
  6. }

可以看到打开文件模式是 OpenOrCreate,其实这里应该用 FileMode.Create,否则就会存在此BUG。

关于 web.config 需要注意的地方

我遇到的错误之一就是请求的流长度过长。由于提交是需要POST过去的,所以请求的内容长度将会视提交的内容而变化。我第一次提交过去是整个解决方案提交的,整个包是4.1M,于是便出错了,无法提交。在IIS7或以上长度限制默认是256K,IIS6是4M。要修改很简单,打开web.config,在 <system.web> 节下面加上一个子节:

  1. <httpRuntime maxRequestLength="102400"/>

这里修改为100M——似乎有点大,但是老衲认为并没有很大问题。值得注意的是,在IIS7以上平台运行时,即便做过这样的设置,限制还是有的,并且不是100M,而是大约28.6M左右,这是因为在IIS7或以上的服务器还有一个 maxAllowedContentLength 限制,这个默认值是 30000000,单位是字节,大约就是 28.6M。所以要突破此限制,<system.webserver> 这里也要一并添加:

  1. <security>
  2.     <requestFiltering>
  3.         <requestLimits maxAllowedContentLength="102400000"></requestLimits>
  4.     </requestFiltering>
  5. </security>

至此,这个问题便可以解决了。

汉化成中文版

Bonobo Git Server 自带了多语言机制,所以很容易翻译成中文,只要对 Resources.resx 加上一个 zh-CN 的区域设置就可以了。不过在它的代码中,取当前用户语言用的是 Request.Languages 进行获得的,并且取的是前两位代码,而不是全部;换句话说,我设置自己的浏览器区域为 zh-CN的话,它识别的区域其实是 zh。关于这点我就很费解了,因为除了英语以外,它还自带了 cs-CZ 语言(原谅我不知道这个是哪国的),照此设置的话其实这个语言在客户端浏览器设置为 cs-CZ 为首选语言时是无法自动切换的(不过并不影响手动切换)。

因为上面的原因,我对源码进行了点点的修改,切换语言用的是完整的区域代码,并且没有标记语言时使用服务器默认的语言,而不是英文。前台的页面和样式表也进行了部分的修改,去掉了图标展示……个人感觉图标太不直观啦,太小了。还有就是语言需要手动加上,这个不够方便。

截图如下:

image

下载链接:http://www.u-tide.com/fish/Service.asmx/Download/39/39

发布页面:http://www.u-tide.com/fish/soft/bonobo_git_server_mod/

更改说明:
[!] 基于 2011.04.13 源码版本构建
[+] 修正保存配置时可能会破坏配置文件的BUG
[*] 修改设置语言时设置的区域代码
[*] 修改了web.config 中关于文件长度限制的配置
[*] 修改了前台页面和样式表中关于语言切换的内容
[+] 增加了简体中文的界面语言

使用说明
————————————————————
解压Patch下的文件并覆盖服务器软件根目录覆盖已有文件即可。

注意
1.如果有自行编译过项目,请将App_GlobalResources下的文件加入项目后重新编译,而不要使用包中的bin下的文件,以防更改丢失;
2.如果有自行修改过web.config,请不要覆盖已有的 web.config ,以免配置丢失;
3.如果有自行修改过前台界面,请确认修改不会和补丁包中的文件冲突。

相关链接

本日志备份自 QQ 空间,原文地址:http://user.qzone.qq.com/286495995/blog/1311053895

喜欢 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址