问题
I have a static class that sends emails with links to certain pages of my site. That link is getting dynamically generated with this code:
UrlHelper urlHelper = new UrlHelper(HttpContext.Current.Request.RequestContext);
string url = urlHelper.Action("Details", "Product", new { id = ticketId }, "http");
The problem is I now also have a service that periodically compares the creation date with the current date and sends those mails automatically. The code crashes of course and says HttpContext.Current
is null (because it ain't a request).
I tried some things like that:
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;
}
}
But when I need RequestContext the second time for the UrlHelper.Action crashes saying Null Reference Exception.
I failed to somehow save/remember/pass the UrlHelper or the HttpContext to have access when calling the mail method over my service.
回答1:
Thanks for all your help. Predefining the URL was no option in my case. I found more or less a solution for my problem. I know it might not be the most beautiful code but it works quite well and noone seems to have a better one, so no downvotes please.
In global.asax.cs I added this class:
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);
}
}
}
}
}
And I added this:
void Application_BeginRequest(Object source, EventArgs e)
{
FirstRequestInitialisation.Initialise(((HttpApplication)source).Context);
}
Explaination what happens: On each and every request the FirstRequestInitialisation class gets called with the method Initialise with the context as parameter. This is never a problem because the context is known in a Application_BeginRequest (not like in Application_Start). The Initialise Method takes care that still the Thread is just called once and has a lock so that it will never crash. I eliminated my Service because I can't really communicate with it and instead I decided to make a Thread out of it. In this Initialise Method I call a class constructor EscalationThread with the host as parameter. In this constructor I create and start the thread that just keeps running.
I still don't have HttpContext and can't use the UrlHelper BUT I have the host and can do stuff like: string urlInMail = this.host + string.Format("/{0}/{1}/{2}", "Product", "Details", product.Id);
来源:https://stackoverflow.com/questions/18151014/mvc-urlhelper-called-from-service