I want to send a bunch of emails, and the obvious way to format them is to render a partial view and send that. The problem is that I'd like to do this in the background, so it isn't immediately obvious how to get access to the methods I need.
Since the job is kicked off by a controller, one thing I was thinking of was something like this:
public ActionResult SendEmails(){
Task.Factory.StartNew(() => DoSendEmails(
// pass in a formatting closure that has access to the
// controller's context
delegate(EmailData) {
return RenderPartialToString("view", EmailData);
}
));
}
Will this work? Is there a better way?
Another option to consider is Postal. You can find a tutorial here to get started, or watch this video from MvcConf. You can send emails asynchronously using the Email.SendAsync() method.
I wrote a project called ActionMailer.Net that allows you to generate emails from your MVC views. Give it a spin and let me know if you like it. I also wrote up some documentation and a nice screencast for the project. Cheers! :)
I would hyper strongly recommend you MvcMailer (note the Send Email Asynchronously section). You may also checkout Scott Hanslemann's blog post about it.
Related
I'm building my first API and I'm wondering what the best approach here is. I have an object with a boolean fiels "isArchived". When the user clicks "Archive" on the object, I'd like to flip this boolean. My question: Can I just call something like:
PUT /api/objects/archive/1
which would hit a controller with logic like this:
[ActionName("archive")]
public HttpResponseMessage ArchiveObject(int id)
{
if (!ModelState.IsValid)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
_service.ArchiveObject(id);
return Request.CreateResponse(HttpStatusCode.OK);
}
or is it better to PATCH via something like this:
PATCH /api/objects/1
and then send some data in the body like
{isArchived: true}
It seems like the latter is more expensive since we're sending data instead of just an id. What's best, and why?
What is RESTful is the basically the question here.
If you want really deep fun explanation I strongly suggest that you check this epic and famous REST "article": How I Explained REST to My Wife
So back you your concrete question. In the spirit of the REST you should create a proper "resource". In your case that means the "archive object" resource. And you just apply the HTTP verbs against it. This is in essence a RESTful service.
If you try like you are trying to give an action a name, you are probably on the wrong path.
So what to do? Create "archive object" WebAPI controller and then, I presume, depends weather the function is idempotent user the proper HTTP verb. POST for create, PUT for update scenario (idempotent function). Do not forget to return in POST (create) scenario the new resource URI. But as far as I can see form your code you are up to the PUT scenario. Since you are able (I presume) to archive object many times.
How to sent additional data (in your case {isArchived: true}) to the API? Simpy, just put those kind of data into the body of the request. That's why we have the body message in HTTP requests.
So, your PUT URI should look like:
PUT /api/objects/achive/1
So that mean that you have object controller as well as "archive controller". Great is't it? And if you do the proper REST the API is really beautiful and easy to understand and use. This is all about of RESTful services.
In my webapplication, I always reply with JSON to AJAX calls.
Thus I find myself doing this on a lot of actions:
if ($request->isXmlHttpRequest()) {
$this->getResponse()->setHttpHeader('Content-type', 'application/json');
return $this->renderText(json_encode($details));
}
Is there a way to get that automatically: anytime the request is AJAX, the content type is JSON?
I was thinking I should use a filter maybe but I am not familiar with filters and maybe there is a better solution.
Any suggestion will be more than welcome.
Thanks,
Dan
The way I solved it:
Create a new class myActions which extends from sfActions. In this class create a new function renderJson($data):
protected function renderJson($data) {
$this->getResponse()->setHttpHeader('Content-type', 'application/json');
return $this->renderText(json_encode($data));
}
Now let your controller class inherit from myActions (instead of sfActions). And at the end of your controller just return $this->renderJson($data);.
(I also did some templating. in the renderJson, if the sf_debug is set in the config, and it's not requested through XmlHttp.)
I'm using a similar technique in one of my projects, but I'd suggest also taking a look at this article regarding iPhone optimization. You can set your routing to accept a format and return the appropriate template based on that. Then you don't need to set the header as it's set by the requested format.
Of course, this means you'll need to create separate template files for each output template, which seems a bother, or use a particular layout file and skip the template. So in the end it may amount to pretty much the same thing (or same amount of code, at least).
I'm new to mvc, mvp or whatever you want to call them. Right now I try to implement a ReservationController where the user first selects a date and then gets a list of suitable time suggestions. As you should know, the suggestions depend on the selected date. This is where my problem / question starts. Should I:
1) Put an event in the View interface like DateChanged and then subscribe to it in the controller?
2) Call UpdateSuggestions on the controller from my asp page, when the selected date changes. (then I must make the controller method public)
Or
3) Update the suggestions in the constructor of the controller.
Regards and thx for help
eric
You need to get out of the control events mind-frame which drives ASP.NET web forms. Although it is technically possible to accomplish things this way I would suggest going down a different route.
You need to return a view to the user which lets them enter a date into a form. They then post the form back to the server and another action method handles this post. This method gets the list of time suggestions and returns a view with these times as its model.
Take a look here for some decent videos on MVC basics: http://www.asp.net/mvc
Here's some great examples of ASP.Net MVC that are great reading for anyone just getting started.
http://www.asp.net/mvc
http://www.asp.net/mvc/tutorials/getting-started-with-mvc3-part1-cs
These two samples include books that take you step by step through creating an MVC project:
http://nerddinner.codeplex.com/
http://www.asp.net/mvc/samples/mvc-music-store
This may not answer your question directly BUT going throught these samples should help make it clear how MVC works and specifically how to use it in ASP.Net. :-)
Here's also a little background on the MVC pattern.
http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
http://msdn.microsoft.com/en-us/library/ff649643.aspx
You should put a link or form in your view that points to a URL that passes the date to an action in the controller.
This action should take the date as a parameter, fetch the data for that date, and pass it to a separate view that renders the data.
You should learn the basics of HTTP and web pages, as well as the underlying design of ASP.Net MVC.
Writing code in a framework or system that you don't understand is a recipe for frustration and disaster.
Sorry but your knowledge in asp.net mvc is very very poor. Better to get some knowledge better, or you cannot make it work. But anyways
1) There do not exist events in views in mvc
2) View does not call contstructor on controller
3) see first two
I think your are misunderstanding how MVC works.
If you are not clear on how MVC works it would be worth checking out something like nerd dinner and Scott Gu's blog.
You could have your dates link to an action like below to process this:
[HttpGet]
public ActionResult YourAction(DateTime date)
{
// Add action logic here
Manager suggestions = new Manager();
var suggestions =suggestions.UpdateSuggestions(date)
// create view model
MyModel model= new MyModel(suggestions);
return View(model);
}
what are your top lessons learned when starting asp.net mvc that you would highlight to someone starting out so they can avoid these mistakes?
Use Html.Encode() everywhere you print data, unless you have a very good reason to not do so, so you don't have to worry about XSS
Don't hardcode routes into your views or javascripts - they're going to change at some point, use Url.Action() instead
Don't be afraid of using partial views
MVC is no silver bullet, first evaluate if it's indeed the best tool of choice for solving your problem.
Don't forget the "Unit Tests" part of the pattern.
Try to always use a ViewModel to pass data between the Controller and the View.
You may think you don't need one, you can just pass your model around, but suddenly you need a list box with several options for editing a model, or displaying a message (not validation message) and you start adding items to the ViewData, with magic strings as keys, making the app harder to maintain.
There are also some security issues that you solve with a ViewModel.
For instance:
class user:
int id
string name
string email
string username
string password
Your view let's the user change his name and email and posts to the action
public ActionResult Edit(User user)
{
--persist data
}
Someone could tamper your form and post a new password and username and you will need to be very careful with the DefaultBinder behavior.
Now, if you use a ViewModel like:
class userEditViewModel:
int id
string name
string email
The problem is gone.
Whenever it is possible make your view typed
Avoid logic in your views
stay away from the HttpContext
Get Steve Sandersons Pro ASP.NET MVC Framework
Debug into the Sourcecode
If you make a Controller method with a different parameter name from id for a single parameter method, you have to make a new route. Just bite the bullet and use id (it doesn't care about the type) and explain it in the comments.
Makes sure you name your parameters with RedirectToAction :
return RedirectToAction("DonateToCharity", new { id = 1000 });
You lose your ViewData when you RedirectToAction.
Put javascript in seperate files, not into the view page
name of the controller :)
unit test Pattern
Don't use the Forms collection, use model binding.
Try not to use ViewData, create a ViewModel.
If you have a loop or an if in your View, write an HTML helper.
Kindness,
Dan
Don't let your controller become a fat one and do too much work. I've seen 1000+ line controllers in the past and it just becomes an absolute nightmare to understand what's going.
Utilise unit testing for your controllers to ensure that dependencies are kept under control and that your code is testable.
Don't get drawn into letting jQuery and fancy clientscript define the behaviour of your application, try and use it as sparingly as you can and let it enhance your application instead.
Use partial views and HTML helpers whenever possible to ensure that your Views do not become unwieldy and a maintenance nightmare.
Use a ViewModel whenever possible.
Use a dependency injection framework to handle your dependencies (MvcContrib has several controller factories, though it's simple enough to roll your own).
Use a different controller for every section of your site (e.g., Home, Account)
Learn how to use ViewData and TempData
Learn what's the use of RenderPartial
Just wondering what people think about creating an area to hold/manage json based requests (note I am thinking mostly get data not post data). I know its not your typical use of an area (i.e. normally you would create a different area for blog vs forum) but I am getting to the point where my project isn't huge but I definitely have a a lot of json stuff which seems to be confusing the issue and is making things look "unclean".
For instance, at the bottom of each controller is where I am putting json actions and so that they don't get mixed up with the other actions I prefix them with json - I shouldn't have to do this... Also I have specific view models for json which I have to prefix with json as well... etc, etc.
It would seem much cleaner to have them off in their own area and be able to drop the json prefix all together and have that defined by the area... what do you think or is this a bad idea?
Cheers
Anthony
I think it's a good idea. Having an asynchronous area where all controllers implement only asynchronous actions will certainly clean up your code. The problem will come when your project does become so big you want to expand into regular areas, then you'll end up with some naming conventions that might end up a bit messy.
You could also just create a separate controller for your json actions. I think this makes more sense than creating an area. Do you need json specific views, content, model etc or just some asynchronous actions?
I think that it's not nessesery to create separate area or even separate actions. If the actions return the same data and differ only in the type of the request - ajax or non-ajax you can just check what is the request and use the corresponding data format.
public ActionResult Index()
{
MyViewModel model = DataAccess.GetMyViewModel(); // Data access code
if (Request.IsAjaxRequest())
{
return Json(model);
}
else
{
return View(model);
}
}