I'm looking for some help wrapping my head around a good approach/architecture to handle images in my ASP.NET MVC 2 application. The application is a client for a middle-tier web service application that encapsulates our domain logic and rules. The images are stored in a back-end database that is only accessible through the web service.
For the sake of this discussion, we'll use the classic case of a Product which has an associated image. Whenever I display information about the Product, I also show the image. So, for instance, when viewing a list of Products to an admin for editing, I will show the image and the name of the product as a hyperlink. when editing, the user can see the existing image and upload a replacement. I also show the image when users browse lists of Products or look at what items are in their 'shopping cart'.
Needless to say, I have to obtain the image data a lot. (And, yes, caching will be a part of the solution but not part of my question.)
My first task was to create the controller and views used to edit Product data which includes the ability to upload the image. I followed the approach described in Pro ASP.NET MVC 2 Framework where I set the image element's src to a controller action which returns the image data. The controller receives a reference to the ProductManagementServiceAgent in its constructor and delegates to the agent which handles the call to the web service. This works great but, of course, it means two calls back to the service to display the information.
Next I have to display the list of Products, with images, to the admin. In this case it's not a problem because I'm using the same controller with the same action, so I can use the same approach. Unfortunately, now I'm making 'n+1' calls to the service.
My quandry comes when figuring out how best to handle all of the other use cases where I need to display the image. Inside the 'shopping cart', for instance. Should my ShoppingCartController also reference ProductManagementServiceAgent and use the same method to retrieve the product image? This would mean any controller that displays a product image would have to reference the agent, yes?
The first thing that bothers me about this is that I don't like injecting multiple dependencies into a class if I really don't need to and see long parameter lists in constructors as smelly code (tells me the object is trying to do too much). Plus, the ProductManagementServiceAgent is really intended for the admin UI, so maybe a different agent would be better? Or a different approach all together?
I have to think that others have already charted this territory, so I appreciate any wisdom to set me in the right direction.
Have a dedicated controller for images.
It will have one dependency - the ProductManagementServiceAgent.
Cache it both server side and client side to minimise requests.
I actually went with a suggestion not posted to this site so I can't give proper credit. In a nutshell, we expose additional actions on our controller when an image is required. So, for instance, our ProductController has a ProductImage action method that accepts the product id and returns the image. It seems to satisfy our needs.
Related
I have an application with several controllers dedicated each to its own part, say, "news", "articles" and "shop". They are not connected to each other, but they should be, as I need to insert data from them, like news related to current shop category. I have not found a clean way to access controllers other than the current one that is handling the request.
The structure of the modules is:
Site.pm is the main project file.
Articles.pm handles articles.
News.pm handles news.
Shop.pm handles shop.
Site.pm loads each of the above dynamically from an array of module names and calls its register function to set routes up and other things at startup. Articles, news, etc all take content from database, and it is rendered as inline template, thus, I can't just take related news and slam them into the stash, as not all entries in shop might even need that information.
This is a theoretical answer without code.
You probably have the database stuff decoupled from the actual controllers as models. That's good.
So let's assume we're in the shop and we want to show news related to the current product. There are at least two ways to do that.
You call your models directly. Your model for news provides a way to get the news for a product. You do that in the shop controller that displays the product page. This controller needs to put the stuff in the stash so the templates can access it.
You create a method in your news controller that is not accessible from the outside. You make it take a product id and find related news articles and populate them into the stash. You forward to it from your product page controller in the shop controller. Afterwards, the product page controller continues. This is the more decoupled way.
In both cases, your shop template includes another template that knows how to deal with the stuff in the stash for displaying news. You might be able to recycle a news template here.
I have not worked on Mojolicious but IMO this is the best approach -
Your Site controller should send GET requests to whatever other controllers it wants and these controllers should return JSON data which can then be rendered at the client side. Take a look Rendering JSON. Hope that helps.
Based on my experience, coding-blood, and a lot of shame for my code, I advise:
each method in a controller should only call a single function and pass the results to the template. This is somehow similar to the answer of #simbabque.
This will help you later testing the controller, writing API instead of providing html templates, even change the framework completely (as long as it is Perl).
So, I would add an optional layer between the Controller and the Models:
$t->get('/books/:id')->to('books#get')
sub Books::get{ my $self = shift; my $book = FBooks::get($self->param('id')); # plus template call }
sub FBooks::get{ # here you call your Model }
# your Model calls your DB
You provide the FBooks::get only then, when you need to make multiple calls to your model/s (maybe this is not a perfect example, but I hope you get my point). I prefer this instead of an army of helpers. If there is any other better way, I am happy to learn it.
My app uploads an image and stores the image info in the database. If needed it manipulates the image. There are several points in the site where images can be managed like this.
In each case I have an action imageuploadAction() that handles things. Because I have slightly different requirements depending on the part of the site the image is going to be used in there are several different imageuploadActions in various controllers of the site. I want to combine them all into one, however, to make the app easier to manage.
So, my question is what is the best way to handle a site wide image upload capability within Zend Framework? I feel it must either be:
Have one action that does it all and the various controllers would use that action, or...
Create some sort of plugin that does it. An Action Helper Plugin perhaps? Maybe a controller plugin of some sort? What sort of plugin is the best way to do this?
I'm inclined to think 2 is the way to go but want your feedback on this. Thanks!
Oh, and the plugin (or action) will handle physically uploading the photos, categorizing them, flagging them for various uses, resizing as needed, passing data to the DB for all CRUD actions as necessary, etc. etc.
What you are describing is what action helpers were designed for, so I'd suggest creating an action helper for handling uploads and moving as much of your processing code into that as possible. However you still need to call that helper from your controllers, so then it really comes down to what suits your application - a central controller that handles the uploads (by calling your helper) or calling the helper from the relevant points in your existing controller methods.
If you can get to a point where your image upload actions are as simple as this:
public function imageuploadAction()
{
if ($this->_helper->HandleImageUpload([...])) {
[...]
}
}
then I'd say you're in pretty good shape, and you can always reuse the helper elsewhere if any parts of your app need to handle an image upload and some other data in the form at the same time.
I'm an absolute beginner with ASP.NET MVC and I'm trying to build a pretty simple application, but I'm having a hard time getting out of the webforms thinking.
I need to register users so they can download my application. I need to capture their information in three screens. Rather than write the database from each view, I want to aggregate all of the data they enter and let them confirm it before they submit their information.
I've been playing with various models and such but if I make one big model, the scaffolding wants to put all the fields on one view.
Can anyone point me in the right direction?
Sounds like you need a Wizard. Here's a few samples:
http://highoncoding.com/Articles/647_Creating_Wizard_Using_ASP_NET_MVC_Part_1.aspx & a youtube video
http://shouldersofgiants.co.uk/Blog/post/2009/09/18/A-RESTful-Wizard-Using-ASPNet-MVC-2e280a6-using-Data-Annotations.aspx
ASP.NET MVC is stateless, which means it doesn't save state between views like Webforms does.
You should save the information from each view into the database, and then set a flag in the user's database record at the end, indicating that the user confirmed their information.
If you need three separate views, you can always copy parts of the code created by the scaffolding to each of the three new views, using only those fields you want the user to see in each view.
If you need validation in each view, use a ViewModel object for each view that pertains only to those fields in the associated view.
I'm developing an ASP.NET MVC application where the content for any page can be pulled from the database, if it exists, and displayed on the page.
This is to make it possible for non-technical persons to edit the content without having to go into the source code (e.g. views) and change things.
The way I'm doing this is, each controller derives from a base controller. The base controller overloads 'OnActionExecuted' and takes this opportunity to pull any content assigned to the current Action/Controller.
If the action returns a ViewModel that derives from 'ContentViewModel', it populates the 'Text' property of the ViewModel with the text from the database.
And then the text gets rendered by the View.
Can you see any weakness to this design?
Would it be better if, rather than having a base controller, I had HtmlHelper extensions for pulling content, which I call from the View?
One reason I'm asking this is, having my own base controller seems to interfere with calling 'Html.RenderAction', which seems to expect the specified controller to directly inherit from 'System.Web.Mvc.Controller'.
ActionFilters should not be used to pull the content.
Controllers should not be used to pull the content but only to dispatch the incoming requests by applying simple logic.
HTML helpers should not be used to pull any content. They are meant to render UI elements prefilled with the supplied data.
application where the content for any page can be pulled from the database
That's basically how most applications operate.
This is to make it possible for non-technical persons to edit the content without having to go into the source code (e.g. views) and change things.
For non-technical persons to edit content there should be an appropriate UI. Independently of the project underlying technology, non-technical personal is never supposed to edit the code.
I suggest you don't make anything weird but keep things clear. Implement your business layer that will supply the data to models which the view will render. Create a UI for other people to edit the content.
I am in the process of building a website content management system for one of my clients. It's a highly customized system, so I cannot use any "of the shelve" solution.
I need to allow my client to add pages to the website on the fly. I have two options here:
(1) Create a database driven page in the format of www.mycompany.com/page.aspx?catID=5&pageID=3 (query the database with the category and page ID's, grab the data and show it on the page) - or -
(2) Allow the management system to create static pages, something like www.mycompany.com/company/aboutus.aspx and www.mycompany.com/company/company_history.aspx , etc.
I believe that, while the former is much easier to implement, the latter is a better both for the user AND for Google.
My questions are (finally): (1) Would you agree that the latter is a better solution, and (2) What is the best way to implement such a solution? Should I create and update each file using the FileSystem (i.e. - the site's management system requires the user to supply a page/file name, page title and content, and creates the page on the fly based on these parameters)? Is there a better way?
Thank you!
It's entirely possible to have database driven pages with nice URLs. StackOverflow itself is a great example - this question's URL is http://stackoverflow.com/questions/1119274/adding-pages-on-the-fly-with-a-cms-system, but the page is built from the database, not static HTML.
I would use the first solution, but mask the addresses using a custom request handler. Basically, give each of your pages a unique string ID (such as about-us) and then, with your request handler that takes all requests, find this particular page in the database and render it.
See this article for some additional info (found it when googling for custom http handlers in ASP.NET.) In that article, it has the following handler added:
<add verb="*" path="*.piechart" type="PieChartHandler"/>
You would probably want to catch all paths (*), excluding certain media paths used for CSS, images and JavaScript.
More resources:
Custom HTTP Handler
HttpHandler in ASP.Net
I'd stay clear of static pages if I where you. Dynamic Data, MVC and some good planning should take you a long way!
What you need to do is to create some or many templates that each view/controller in mvc can use. Let whoever is responsible for the content handle it through dynamic data entities.
I would use the first idea, but work out a better URL scheme. If the system doesn't provide nice URLs (without ?), you'll have trouble getting the search engines to parse the whole site. Also using numbers instead of words make it hard on users to pass around URLs.
If you start to have performance problems you could add caching that would generate static pages from time to time. I would avoid doing that until you have to; caching can cause many headaches along the way to getting it right.
Although the existing advice is more-or-less sound, the commentators have failed to consider one factor which, admittedly, you haven't given much detail on. Are these pages that they'll edit once they're built, or a they one-shot creations? If the latter, your plan of generating static pages isn't quite so bad as they suggest. Why bother even having to think about database schemas and caching, when you can just serve flat content.
It will probably make for pretty lifeless, end-of-the-road pages, but if that's what you want ...