17

I am using quartz.net to schedule regular events within asp.net mvc application.

The scheduled job should call a service layer script that requires a UrlHelper instance (for creating Urls based on correct routes (via urlHelper.Action(..)) contained in emails that will be sent by the service).

I do not want to hardcode the links into the emails - they should be resolved using the urlhelper.

The job:

public class EvaluateRequestsJob : Quartz.IJob
{
    public void Execute(JobExecutionContext context)
    {
        //  where to get a usable urlHelper instance?
        ServiceFactory.GetRequestService(urlHelper).RunEvaluation();
    }
}

Please note that this is not run within the MVC pipeline. There is no current request being served, the code is run by the Quartz scheduler at defined times.

How do I get a UrlHelper instance usable on the indicated place?

If it is not possible to construct a UrlHelper, the other option I see is to make the job "self-call" a controller action by doing a HTTP request - while executing the action I will of course have a UrlHelper instance available - but this seems a little bit hacky to me.

Marek
  • 10,307
  • 8
  • 70
  • 106
  • 1
    Wow the negative votes are flying out on this thread :) – Kelsey Mar 09 '10 at 22:15
  • @Kelsey maybe it is because the question seems to be too trivial so people tend to give trivial or irrelevant answers or the question requires at least basic knowledge of not so well known framework (quartz) – Marek Mar 09 '10 at 22:18
  • Does this quartz scheduler use something similar to the method that Jeff made a post on: http://blog.stackoverflow.com/2008/07/easy-background-tasks-in-aspnet/ ? – Kelsey Mar 09 '10 at 23:27
  • The problem with most of the answers so far is they assume the quartz task will run in a user request which it won't, the likes of HttpContext.Current just won't work properly. The problem is similar to that of cache expiry events (which also don't run as part of the the user's request). – Duncan Mar 09 '10 at 23:47
  • Possible duplicate of [Call UrlHelper in models in ASP.NET MVC](http://stackoverflow.com/questions/2031995/call-urlhelper-in-models-in-asp-net-mvc) – Sheridan Apr 19 '16 at 08:44

4 Answers4

7

How about just creating a new HttpContext for the UrlHelpler as in this answer:

Community
  • 1
  • 1
Duncan
  • 2,493
  • 2
  • 17
  • 13
  • Meanwhile I have used a different approach, but this one seems like it may work, even if it is a little hacky. Thanks for finding the answer :) – Marek Mar 24 '10 at 07:50
  • @Marek - How did you solve your problem? I am having similar problem where I need HttpContext to render a view as I use that view to send out a email once quartz is done. – chobo2 May 22 '11 at 00:37
  • @chobo - I ended up creating an external app that performs recurrent http requests and implemented the logic in controller actions. – Marek May 23 '11 at 07:46
  • This shouldn't be an accepted answer. Creating the HttpContext manually and considered that you now need to use an hardcoded url. I want to use the UrlHelper to get the host, which can be dynamically. Therefore won't work this way. – liqSTAR Jan 09 '23 at 10:08
2

Edit: Sorry I totally mis-read the question I guess.

It sounds like your scheduler (which I have no idea how it works) is a seperate process and you want the UrlHelper to help generate valid URLs in your MVC app?

You could try writing a handler in your MVC app that will be running under your applications context that will build the URL for you and return it. You could then call the handler from your scheduler to get any URL you need based on the params you pass in. This way your scheduler just needs to know about where the query URL of your MVC app is and then can ask it to do the Url mapping for you.

Hope this is a bit better of an answer. If I am totally off let me know... was going to delete my response but thought I would give it one more shot.

Kelsey
  • 47,246
  • 16
  • 124
  • 162
  • thanks, the idea of having only a single "hardcoded" well known url that provides the required route mappings is interesting - even if it is equivalent to calling an action that will fire off the evaluation service with a HTTP request. undoing my downvote now :) – Marek Mar 09 '10 at 22:23
  • Ya I can't think of any other way of doing it because your MVC app is really the only thing that is going to have access to the context you need. It's an interesting problem that I have been getting around with using hardcoded URLs in a config file where I leave `{0}` arguments to be substituted based on IDs. Never liked the solution so I am interested to see if there is a better way to do it. – Kelsey Mar 09 '10 at 22:27
  • Please note that this code is still running inside the MVC app - but not serving any requests. IF I could capture *any* request and store the UrlHelper instance to a known place, problem would be solved (yes, that smells a lot) – Marek Mar 09 '10 at 22:32
  • This answer sounds reasonable enough. If, upon timer elapse, you simply call some URL on your own app that'll build and return you the built URL that you're looking for. – p.campbell Mar 09 '10 at 23:23
0

Remember to specify the protocol parameter when using UrlHelper.Action method, this will generate absolute urls. Example:

url.Action("Action", "Controller", null, "http")

or

url.Action("Action", "Controller", null, request.Url.Scheme)
Shelakel
  • 1,070
  • 9
  • 16
-2

You need a RequestContext to create a UrlHelper. In one of my HtmlHelper extension methods, I do it like this:

public static string ScriptUrl(this HtmlHelper html, string script)
{
    var url = new UrlHelper(html.ViewContext.RequestContext);
    ...
}

How you get the RequestContext is dependent on your application.

Gabe Moothart
  • 31,211
  • 14
  • 77
  • 99
  • Could you please specify how do I get the HttpContext in the example I have posted? The problem seems to be equivalent to my original problem - I am not within the MVC request processing pipeline, the scheduled job is called from the Quartz scheduler. – Marek Mar 09 '10 at 21:54
  • Outside the MVC pipeline, I'm not sure. You would probably need to manually set up your routes, etc., as the framework isn't doing any of that for you. It's probably possible, but doesn't sound worth the hassle. – Gabe Moothart Mar 09 '10 at 22:01