Asp.net 伪造MVC服务器.Transfer:Response.End()不会结束我的线程

Asp.net 伪造MVC服务器.Transfer:Response.End()不会结束我的线程,asp.net,asp.net-mvc,server.transfer,Asp.net,Asp.net Mvc,Server.transfer,我这里有两个问题,如果第一个问题得到了回答,那么第二个问题就无关紧要了,但在我看来,技术上仍然很有趣。。。我将尽可能清楚地说明: 第一个问题:我的目标是伪造一个服务器。在MVC中传输,有没有什么方法可以做到这一点,我找到了很多关于它的文章,但大多数都是关于重定向/重新路由的,这在我的情况下是不可能的(至少我想不出来) 这里是上下文,我们的网站有两个版本,一个是“桌面”版本,一个是移动版本。我们的营销人员希望在同一个url上提供两个版本的主页(因为SEO专家这么说) 这听起来琐碎而简单,在大多

我这里有两个问题,如果第一个问题得到了回答,那么第二个问题就无关紧要了,但在我看来,技术上仍然很有趣。。。我将尽可能清楚地说明:

  • 第一个问题:我的目标是伪造一个服务器。在MVC中传输,有没有什么方法可以做到这一点,我找到了很多关于它的文章,但大多数都是关于重定向/重新路由的,这在我的情况下是不可能的(至少我想不出来)
这里是上下文,我们的网站有两个版本,一个是“桌面”版本,一个是移动版本。我们的营销人员希望在同一个url上提供两个版本的主页(因为SEO专家这么说)

这听起来琐碎而简单,在大多数情况下都是这样,除了。。。我们的桌面站点是.NET4.0ASPX站点,我们的移动站点是MVC,两者都运行在同一个站点(同一个项目、同一个应用程序池、同一个应用程序)

因为桌面版本代表了我们95%的流量,所以这应该是默认值,并且只有当用户在移动设备上或者真的想查看移动版本时,我们才希望从ASPX代码“传输”(因此是相同的url)到MVC视图。就我目前所见,没有简单的方法可以做到这一点(Server.Transfer只执行一个新的处理程序——因此是页面——如果它有一个物理文件的话)。因此,到目前为止,有人以适当的方式这样做了吗

这让我想到:

  • 第二个问题:我确实构建了自己的到MVC的传输机制,但后来发现Response.End()实际上不再结束正在运行的线程,有人知道为什么吗
很明显,我并不期望有任何出乎意料的答案,所以我现在做的是:

在需要转移到手机的页面中,我会执行以下操作:

protected override void OnPreInit(EventArgs e) {
  base.OnPreInit(e);
  MobileUri = "/auto/intro/index"; // the MVC url to transfer to
  //Identifies correct flow based on certain conditions 1-Desktop 2-Mobile
  BrowserCheck.RedirectToMobileIfRequired(MobileUri);
}
由RedirectTomobileiFrequeuired调用的实际TransferToMobile方法(我跳过了检测部分,因为它与此无关)如下所示:

/// <summary>
/// Does a transfer to the mobile (MVC) action. While keeping the same url.
/// </summary>
private static void TransferToMobile(string uri) {
  var cUrl = HttpContext.Current.Request.Url;

  // build an absolute url from relative uri passed as parameter
  string url = String.Format("{0}://{1}/{2}", cUrl.Scheme, cUrl.Authority, uri.TrimStart('/'));

  // fake a context for the mvc redirect (in order to read the routeData).
  var fakeContext = new HttpContextWrapper(new HttpContext(new HttpRequest("", url, ""), HttpContext.Current.Response));
  var routeData = RouteTable.Routes.GetRouteData(fakeContext);

  // get the proper controller
  IController ctrl = ControllerBuilder.Current.GetControllerFactory().CreateController(fakeContext.Request.RequestContext, (string)routeData.Values["controller"]);

  // We still need to set routeData in the request context, as execute does not seem to use the passed route data.
  HttpContext.Current.Request.RequestContext.RouteData.DataTokens["Area"] = routeData.DataTokens["Area"];
  HttpContext.Current.Request.RequestContext.RouteData.Values["controller"] = routeData.Values["controller"];
  HttpContext.Current.Request.RequestContext.RouteData.Values["action"] = routeData.Values["action"];

  // Execute the MVC controller action
  ctrl.Execute(new RequestContext(new HttpContextWrapper(HttpContext.Current), routeData));

  if (ctrl is IDisposable) {
    ((IDisposable)ctrl).Dispose(); // does not help
  }

  // end the request.
  HttpContext.Current.Response.End();
  // fakeContext.Response.End(); // does not add anything
  // HttpContext.Current.Response.Close(); // does not help
  // fakeContext.Response.Close(); // does not help
  // Thread.CurrentThread.Abort(); // causes infinite loading in FF
}
//
///执行传输到移动(MVC)操作。同时保持相同的url。
/// 
私有静态无效TransferToMobile(字符串uri){
var cUrl=HttpContext.Current.Request.Url;
//从作为参数传递的相对uri构建绝对url
stringurl=string.Format(“{0}://{1}/{2}”),cUrl.Scheme,cUrl.Authority,uri.TrimStart('/');
//为mvc重定向伪造上下文(以便读取RoutedData)。
var fakeContext=newhttpcontextwrapper(newhttpcontext(newhttprequest(“,url,”),HttpContext.Current.Response));
var routeData=RouteTable.Routes.GetRouteData(fakeContext);
//找到合适的控制器
IController ctrl=ControllerBuilder.Current.GetControllerFactory().CreateController(fakeContext.Request.RequestContext,(string)RoutedData.Values[“controller”]);
//我们仍然需要在请求上下文中设置routeData,因为execute似乎不使用传递的路由数据。
HttpContext.Current.Request.RequestContext.RouteData.DataTokens[“区域”]=RouteData.DataTokens[“区域”];
HttpContext.Current.Request.RequestContext.RoutedData.Values[“controller”]=RoutedData.Values[“controller”];
HttpContext.Current.Request.RequestContext.RoutedData.Values[“action”]=RoutedData.Values[“action”];
//执行MVC控制器操作
Execute(newrequestcontext(newhttpcontextwrapper(HttpContext.Current),routeData));
如果(ctrl可识别){
((IDisposable)ctrl.Dispose();//没有帮助
}
//结束请求。
HttpContext.Current.Response.End();
//fakeContext.Response.End();//不添加任何内容
//HttpContext.Current.Response.Close();//没有帮助
//fakeContext.Response.Close();//没有帮助
//Thread.CurrentThread.Abort();//导致FF中的无限加载
}
在这一点上,我希望Response.End()调用也能结束线程(如果我跳过整个假装的控制器执行位,它也会结束),但它不会

因此,我怀疑要么是我伪造的上下文(这是我发现的唯一能够用新url传递当前上下文的方法),要么是控制器阻止了线程被终止

fakeContext.Response与CurrentContext.Response相同,并且尝试结束假上下文的响应或终止线程的几次尝试并没有真正帮助我

在Response.End()之后运行的任何代码实际上都不会呈现给客户端(这是一个小小的胜利),因为响应流(以及连接,客户端中没有“无限加载”)正在关闭。但代码仍在运行,这是不好的(显然,在尝试编写ASPX页面、写入标题等时也会产生大量错误)

因此,任何新的潜在客户都将非常受欢迎

总而言之: -有没有人能用一种不那么老练的方式在同一个url上共享一个ASPX页面和一个MVC视图? -如果没有,有人知道我如何才能确保我的回答真的结束了吗


非常感谢

我没有做太多的研究,但下面是关于
Response.End()
的情况:

这至少可以提供“为什么”(
\u context.IsInCancellablePeriod
)。你可以试着用你最喜欢的CLR反编译器来跟踪它。

不管谁感兴趣,我至少有问题1的答案:)。 当我第一次使用该功能时,我考虑了以下(非常接近的)问题:

并尝试了Stan创建的传输方法(使用httpHandler.ProcessRequest)和Server.TransferRequest方法。两者都对我不利:

  • 第一个在IIS中不起作用(因为我需要在页面中调用它,这似乎已经太晚了)
  • 第二个问题让开发人员非常恼火,他们都需要在IIS中运行他们的站点(没有大问题,但仍然…)
看到我的解决方案显然不是最优的,我不得不回到IIS解决方案,它似乎是生产环境中最整洁的解决方案

这个解决方案对p
public void End()
{
    if (this._context.IsInCancellablePeriod)
    {
        InternalSecurityPermissions.ControlThread.Assert();
        Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
    }
    else if (!this._flushing)
    {
        this.Flush();
        this._ended = true;
        if (this._context.ApplicationInstance != null)
        {
            this._context.ApplicationInstance.CompleteRequest();
        }
    }
}
private static void Transfer(string url) {
  if (HttpRuntime.UsingIntegratedPipeline) {
    // IIS 7 integrated pipeline, does not work in VS dev server.
    HttpContext.Current.Server.TransferRequest(url, true);
  }

  // for VS dev server, does not work in IIS
  var cUrl = HttpContext.Current.Request.Url;
  // Create URI builder
  var uriBuilder = new UriBuilder(cUrl.Scheme, cUrl.Host, cUrl.Port, HttpContext.Current.Request.ApplicationPath);
  // Add destination URI
  uriBuilder.Path += url;
  // Because UriBuilder escapes URI decode before passing as an argument
  string path = HttpContext.Current.Server.UrlDecode(uriBuilder.Uri.PathAndQuery);
  // Rewrite path
  HttpContext.Current.RewritePath(path, true);
  IHttpHandler httpHandler = new MvcHttpHandler();
  // Process request
  httpHandler.ProcessRequest(HttpContext.Current);
}