【问题标题】:MVC UrlHelper called from Service从服务调用的 MVC UrlHelper
【发布时间】:2013-08-09 16:03:35
【问题描述】:

我有一个静态类,它发送带有指向我网站某些页面的链接的电子邮件。该链接正在使用此代码动态生成:

UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
string url = urlHelper.Action("Details", "Product", new { id = ticketId }, "http");

问题是我现在还有一项服务,它会定期将创建日期与当前日期进行比较并自动发送这些邮件。代码当然会崩溃,并说HttpContext.Current 为空(因为它不是请求)。

我尝试了一些类似的方法:

private static System.Web.Routing.RequestContext requestContext;
private static System.Web.Routing.RequestContext RequestContext {
    get
    {
        if(requestContext == null)
            requestContext = HttpContext.Current.Request.RequestContext;
        return requestContext;
    }
}

但是当我第二次需要 RequestContext 时 UrlHelper.Action 崩溃说空引用异常。

在通过我的服务调用邮件方法时,我无法以某种方式保存/记住/传递 UrlHelper 或 HttpContext 以进行访问。

【问题讨论】:

  • 如果你在一个控制器中,你应该使用 ControllerContext。这段代码在哪里?如果这是在库中,那么您应该将适当的上下文传递给创建 URL Helper 的方法。但是,我看不到服务层中的 URL 之类的特定于 Web 的东西——它应该在您项目的 Web 层中,因为它是 webby 的东西。
  • 我有一个名为 MailMethods 的静态类,它使用 UrlHelper 完成所有发送工作。现在真正的问题是我有一个单独的服务,它在同一个解决方案文件中,可以访问所有公共方法,但当然没有 HttpContext.Current...
  • @yourmother 那么你有一个设计问题。如果您的助手 依赖 HttpContext.Current 那么它应该只在可用的环境中使用 - 或者您应该重构对 HttpContext.Current 的需求。
  • 我同意@James。您需要让控制器将 HttpContext 传递到服务中。
  • 是的,但服务/应用程序如何知道网站的 url(动态)?我怎样才能将它传递给服务?

标签: c# asp.net-mvc httpcontext urlhelper


【解决方案1】:

感谢您的所有帮助。在我的情况下,预定义 URL 不是选项。我或多或少找到了解决我的问题的方法。我知道它可能不是最漂亮的代码,但它工作得很好,似乎没有人有更好的代码,所以请不要反对。

global.asax.cs 我添加了这个类:

class FirstRequestInitialisation
{
    private static string host = null;

    private static Object s_lock = new Object();

    // Initialise only on the first request
    public static void Initialise(HttpContext context)
    {
        if (string.IsNullOrEmpty(host))
        { //host isn't set so this is first request
            lock (s_lock)
            { //no race condition
                if (string.IsNullOrEmpty(host))
                {
                    Uri uri = HttpContext.Current.Request.Url;
                    host = uri.Scheme + Uri.SchemeDelimiter + uri.Host + ":" + uri.Port;

                    //open EscalationThread class constructor that starts anonymous thread that keeps running. 
                    //Constructor saves host into a property to remember and use it.
                    EscalationThread et = new EscalationThread(host);
                }
            }
        }
    }
}

我添加了这个:

void Application_BeginRequest(Object source, EventArgs e)
{
    FirstRequestInitialisation.Initialise(((HttpApplication)source).Context);
}

解释会发生什么: 在每个请求中,FirstRequestInitialisation 类都会使用 Initialise 方法调用,并将上下文作为参数。这从来都不是问题,因为上下文在 Application_BeginRequest 中是已知的(不像在 Application_Start 中那样)。 Initialise 方法注意线程只被调用一次并且有一个锁,这样它就不会崩溃。 我取消了我的服务,因为我无法真正与它交流,而是决定用它制作一个线程。在这个 Initialise 方法中,我以主机为参数调用类构造函数 EscalationThread。在这个构造函数中,我创建并启动了一直运行的线程。

我仍然没有 HttpContext 并且无法使用 UrlHelper 但我有主机并且可以执行以下操作:string urlInMail = this.host + string.Format("/{0}/{1}/{2}", "Product", "Details", product.Id);

【讨论】:

    猜你喜欢
    • 2011-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    相关资源
    最近更新 更多