控制器操作多次出现 - 在Azure模拟器中运行的ASP.NET MVC 4 App

时间:2012-12-08 16:30:39

标签: asp.net-mvc azure asp.net-mvc-4 visual-studio-debugging

这可能需要一些时间来解释,但我在这里:)。

我创建了两个Visual Studio 2012项目:

  1. 在Visual Studio的添加项目对话框中使用(Web - > ASP.NET MVC 4 Web应用程序)模板的项目。我没有添加单元测试项目。
  2. 使用Azure云服务模板的项目(云 - > Windows Azure云服务)。我添加了一个角色,一个ASP.NET MVC 4 Web角色,并且再次没有添加单元测试项目。
  3. 我让这两个项目完全不受Visual Studio为我创建它们的方式的影响。

    对于每个项目,我然后转到HomeController类并在每个AboutContact操作方法中设置断点(无聊的操作,只返回一个视图)。例如,我在方法的唯一一行设置断点:

    public ActionResult About()
    {
         return View();
    }
    

    然后我开始调试第一个项目(非Azure项目)。一切都如预期的那样 - 即当我使用浏览器在“关于”和“联系”页面之间导航时,相应操作方法中的断点将在每个请求中被击中一次。对我来说很好。

    然后我开始调试Azure项目。我遵循了在关于和联系页面之间导航的相同过程。这次我发现了有趣的非确定性行为。在某些请求中,在页面呈现之前,action方法中的断点将被多次(有时多于两次)命中。有时请求会挂起,页面也不会呈现(即使在等待几分钟后)。

    我想知道为什么会发生这种情况,因为它影响了我们正在处理的另一个Azure MVC应用程序中更复杂的事情(例如,由于此问题,应用程序可能会尝试创建两个或者我的数据库中的一个模型对象的更多实例用于一个请求。)

    我在以下环境中:

    • Windows 8 Pro(x64)
    • Visual Studio 2012 Ultimate
    • 适用于Visual Studio 2012的Windows Azure SDK
    • IIS 8 Express
    • 使用Firebug的Firefox浏览器(也确认了使用IE的行为)
    • SQL Server 2012(我猜不太相关)

    我注意到唯一有趣的事情是,每当我调试Azure项目时,Visual Studio中的输出窗口中都会出现以下警告消息:

      

    在角色' My_Web_Role_Name'中重新映射私有端口80到81避免在模拟过程中发生冲突。

    也许这种重新映射与它有关。然后,在执行netstat -ano之后,我看到Azure Development Fabric进程正在侦听端口80,所以也许这就是为什么它需要进行重新映射...听起来很公平。

    无论如何,我希望有人可能知道可能导致这种行为的原因。以下是我尝试过的一些额外点和方法:

    • 重置IIS,重新启动Azure Compute / Storage模拟器,重新启动整个计算机
    • 删除所有脚本的视图(即如果页面上只有一个基本的HTML段落,行为仍然存在)
    • 我试图找到相关的IIS Express日志文件,但似乎Azure项目不像其他项目那样运行IIS Express(这是正确的吗?)。
    • 我监控了Azure Compute Emulator控制台......没有什么非常有趣的。

    所以...最后,有些问题:

    • 其他人可以重现这种行为吗?
    • Azure模拟器生成的任何其他日志是否可以帮助我?

    我非常感谢在这里推进正确的方向:)。

    干杯!

    修改

    这里有更多信息(我在继续调试此问题时更新了这个问题):

    我决定在没有调试的情况下运行解决方案,并在AboutContact操作方法中添加了一些简单的调试消息,例如:

    public ActionResult About()
    {
         System.IO.File.AppendAllText(@"c:\Logs\azure.log", DateTime.Now + ": Contact, thread " + System.Threading.Thread.CurrentThread.ManagedThreadId + "\r\n");
         return View();
    }
    

    我将Tail附加到此文件,并启动Fiddler以查看HTTP上发生的情况。再次在两个AboutContact链接之间导航,我看到了以下输出:

    来自尾巴:

    • ...
    • 9/12/2012 12:14:07 PM:关于,主题7
    • 9/12/2012 12:14:08 PM:联系,第7行
    • 9/12/2012 12:14:09 PM:关于,第7条
    • 9/12/2012 12:14:10 PM:联系,第7行
    • 9/12/2012 12:14:11 PM:关于,主题6
    • 9/12/2012 12:14:12 PM:联系,第8行
    • 9/12/2012 12:14:31 PM:联系,第7行
    • 9/12/2012 12:14:50 PM:联系,第7行
    • 9/12/2012 12:15:03 PM:关于,第7条
    • 9/12/2012 12:15:05 PM:联系,第8行
    • 9/12/2012 12:15:23 PM:关于,主题6
    • 9/12/2012 12:15:42 PM:关于,第14行
    • 9/12/2012 12:16:01 PM:关于,主题6
    • 9/12/2012 12:16:31 PM:联系,第7行
    • 9/12/2012 12:16:33 PM:关于,第14行
    • ...
    • 9/12/2012 12:17:08 PM:联系方式,第12条
    • 9/12/2012 12:17:09 PM:关于,第12条
    • 9/12/2012 12:17:28 PM:关于,主题5
    • ...

    来自Fiddler的相同请求(注意我也一直在玩我的角色端点设置,但无济于事):

    Fiddler screenshot showing HTTP traffic

    所以...这里带回家的消息是:

    • HTTP流量似乎正常(Fiddler未显示任何重复请求)
    • 对于同一请求,行动方法有时会被调用两次或三次,看似不确定(即上述原始问题)
    • 有趣的是,在我的情况下,好像完全 19s经过另一次'击中'在动作方法上发生(即当多次击中动作方法时,命中之间的时差是确定性的)
    • 每当多次触发操作方法时,每次匹配的线程ID通常都不同

    我会继续深入挖掘...也许有人会根据这些更新的信息提供建议:)。

    编辑2 我决定在每种情况下打印出进程ID以及action方法中的线程ID。对于每个请求,进程ID都是与IIS Express Worker Process对应的进程ID。因此,似乎IIS Express工作进程有时会产生多个线程来处理请求,每个线程相隔19秒。

    ...而且我更深入了......:)

    编辑3

    我想我越来越接近这个问题......我看了一下IIS Express托盘,在启动应用程序后看到了以下内容(没有调试):

    IIS Express window showing the IIS Application running under the web role

    我决定直接使用这个URL(而不是如上面的Fiddler所示的127.0.0.2:8888),问题似乎消失了。这现在开始有意义......如果我直接通过端口8889调用IIS应用程序,一切正常,就像它对原始的非Azure项目一样。如果我通过端口8888调用Web角色(即Azure特定部分),它有时似乎多次调用IIS应用程序。

    所以我现在开始缩小对网络角色的关注。我将尝试查看是否可以找到一些相关的Web角色日志......

    编辑4

    我在应用程序上确保diagnostics was set up properly并在调试模式下运行它。然后,我转到Azure Compute Emulator UI,右键单击我的Web角色实例,然后选择" Open Local Store"。这把我带到资源管理器,在那里我能够找到一个子文件夹" temp \ temp \ RoleTemp \ iisexpress"其中包含一个日志文件,其内容看起来像这样(请注意,我已将我的端点更改回端口80,因此IIS Express应用程序现在返回到端口81):

    • 请求已开始:" GET" 127.0.0.1:81/Home/About
    • 请求已结束:127.0.0.1:81 / Home /关于HTTP状态200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/Contact
    • 请求已结束:127.0.0.1:81 / Home / Contact with HTTP status 200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/Contact
    • 请求已结束:127.0.0.1:81 / Home / Contact with HTTP status 200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/Contact
    • 请求已结束:127.0.0.1:81 / Home / Contact with HTTP status 200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/About
    • 申请已结束:127.0.0.1:81 / Home /关于HTTP状态200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/About
    • 申请已结束:127.0.0.1:81 / Home /关于HTTP状态200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/About
    • 申请已结束:127.0.0.1:81 / Home /关于HTTP状态200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/Contact
    • 请求已结束:127.0.0.1:81 / Home / Contact with HTTP status 200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/Contact
    • 请求已结束:127.0.0.1:81 / Home / Contact with HTTP status 200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/Contact
    • 请求已结束:127.0.0.1:81 / Home / Contact with HTTP status 200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/About
    • 请求已结束:127.0.0.1:81 / Home /关于HTTP状态200.0
    • 请求已开始:" GET" 127.0.0.1:81/Home/Contact
    • 请求已结束:127.0.0.1:81/Home/Contact with HTTP status 200.0

    同样,我只是在About页面和Contact页面之间切换,因此从日志中可以看到单个Web角色端点请求有时会导致Web角色多次调用IIS应用程序。现在,搜索一些更高级别的Web角色日志,找出它为什么这样做:)!

1 个答案:

答案 0 :(得分:1)

所以根据我在原帖的各种编辑中所写的内容:

  • 至少在我的机器上,DevFC.exe进程(开发结构,Azure计算模拟器)有时会从IIS Express产生对所请求资源的多个请求。也就是说,它将在模拟器端点上发出单个请求,并且有时会一个接一个地向基础IIS Express应用程序产生多个请求,即使它们都已成功使用HTTP状态代码200.这些生成的请求之间的时间差异似乎要保持不变,但除此之外,行为似乎是非确定性的(即,对于模拟器端点的每个请求都不会发生这种情况。)
  • 为了调试这个,我需要访问Azure计算模拟器的源代码,我猜这是我无法获得的。

现在,我的理论(并希望)是这种行为在某种程度上特定于我的开发环境,并且不会在真正的Azure基础架构上重现。那就是说,我想出了一个解决方法......

我为Firefox创建了一个简单的代理文件,将所有流向我本地Azure模拟器端口的流量重定向到IIS Express应用程序端口。这解决了这个问题,但是我知道我现在基本上绕过了Azure模拟器,我猜我将来可能会遇到问题,因为我正在这样做(例如,如果我决定使用AppFabric缓存? )!

在此期间,我将继续使用此解决方法进行开发,并定期部署到我的Azure临时环境以进行测试。

无论如何,如果有人知道如何解决根本问题,请告诉我! :)

编辑: 我无法再使用Azure SDK Tools 2.2版重现该问题。如果您仍然看到此行为,请尝试升级!