I am trying to build my own CMS for myself and my clients. The system will mainly be used for small websites < 10 pages. For bigger project I will most likely use an existing system(MojoPortals, Umbraco, Kooboo). The reason why I want my own system is so that I have full control and also because existing systems are mostly bloated with features that I wont use anyway for smaller projects. I am also learning Asp.net Mvc so that's the other reason to build my own system.
These are some of the systems I tried(some more than others):
N2
MojoPortal
MVC CMS
Umbraco
Kooboo
The one I liked right away was MojoPortals. Mostly because of the left-middle-right + modules system.
So my goals are to have a system where you can create pages and each page will have a left, middle and right placeholder for modules. The modules will be very basic(Text, Html, Image). The system also need to be easy to deploy and reuse.
I already started working on my system.
The page object looks like this:
public class Page
{
public int PageID { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Title { get; set; }
public IEnumerable<Module> Modules { get; set; }
}
The Module object looks like this:
public class Module
{
public int ModuleID { get; set; }
public string ModuleTitle { get; set; }
public string ModuleType { get; set; }
public string ModuleLocation { get; set; }
public Dictionary<string, string> ModuleValues { get; set; }
}
This is how my View looks:
www.codepaste.com
Later I will probably add a website object that holds info for which view(template) it will show.
The questions I have at the moment are mainly about the view. The view I linked has some basic code which first checks the module location and then shows all the module info in the right location. I would like that part to be easy reusable. So I thought of making a strongly typed partial view that does the left, right and middle stuff. Also for the modules I was thinking of using partial views and render the correct partial of a certain moduleType. So text will have a partial, html will have one and so on. I am not sure if this is the right technique.
So should I use a partial view to handle the left, middle and right stuff and use partial views to load the modules?
If somebody has other info about building a module based cms or techniques/structures that I can use that would be really great too.
Thanks in advance, Pickels.
Yes, that's the best option. Set a "structural base" to each template with css, and make every module load his own views into the right template sections. Lets say you template has a top menu under the common header where you display companie's logo and stuff .. insert in the database the information about the module and about that top section of the template (you should totally create a table in the database about template structure, so the system can know where to put every module related with every page), and just use the system to get the module needed in every page request to the right position, making it load its own view(s) into that place.
Hope you understand my writing :)
Related
For reasons given below, strongly typing the layout seems a logical approach.
But I am scared to ignore the warnings of so many programmers so much more skilled an experienced than myself.
Why do so many recommend avoiding this approach?
Brief Breakdown of Arguments For / Against
I am planning to use a model like this as a base class for my application's ViewModels.
public class LayoutViewModel
{
public string CanonicalURL { get; set; }
public string PageTitle { get; set; }
public string MetaTitle { get; set; }
public string Description { get; set; }
public string OGImage { get; set; }
public string OGType { get; set; }
}
This question generated some sensible sounding arguments against doing so, for example:
"layout is a partial used by all of your views. Specifying a model
there would add restriction to every view on your site to also have
that model."
"you are avoiding one "bad practice" (dynamic typing of ViewBag), but
trying to replace it with another bad practice (tying your layout to
model data). Layouts should not rely on data.."
Ant P suggested: "You should delegate the parts of your layout that
"need a model" to a separate controller using partial views and
RenderAction"
But on reflection, I don't find them convincing:
PageTitle, MetaTitle, Description and OG data are required for
every full page view, so I feel it's proper that the ViewModel should contain
that data.
Why should I avoid "tying my layout to model data"? Is not every MVC view tied to the model it is based on?
ViewBag is inconvenient and error prone
The only disadvantage I see is that layout changes may require changes to the base model also. But this seems minor compared to the advantages a strongly typed _layout.cshtml. And realistically, it's unlikely that the properties above will change any time soon.
I have a small MVC web project where I want to be able to achieve the following:
Select the base page layout and CSS/JavaScript based upon the active domain
Optionally allow this base/default setting to be overridden at the start of the session.
To help achieve this I have created a layout object with the following properties:
public class PageLayout {
public string Reference { get; set; }
public string Domain { get; set; }
public string LayoutPath { get; set; }
public string CssPath { get; set; }
public string JavaScriptPath { get; set; }
}
My idea being that at the start of the session, the URL will be checked for a layout parameter. For example:
http://www.{Domain}.com/tech
In this instance, the Pagelayout object with the Reference "tech" would be retrieved. If no parameter was found then the Page Layout object with its Domain property matching the active domain would be retrieved.
I have several questions regarding the right way to implement this:
Where is the best place to implement this logic in MVC? The Session_Start method in Global.asax seems like a potential candidate
I want to persist the retrieved PageLayout object across the whole session. I was going to add it to the Session state via some kind of management class.
How do I make the Pagelayout data available to each page. I thought about creating a custom Controller and then adding it to the ViewBag (from the Session), so the master view could implement something like the following:
#{
Layout = ViewBag.Pagelayout.LayoutPath;
}
...
Are the better/cleaner/more appropriate mechanisms available to achieve what I need?
Yes there are cleaner ways to do, like using some third party tool and to hook it your application.
You can take a look at this site, this is the latest that have been introduced recently
http://razorc.net/
Also take a look at
http://www.codeproject.com/Articles/32847/ASP-NET-MVC-Dynamic-Themes
http://codeofrob.com/entries/dynamically-switching-between-master-pages-in-asp.net-mvc.html
I have a model that looks like this:
public class Book
{
public string Name { get; set; }
public IEnumerable<Author> Authors { get; set; }
}
public class Author
{
public string FullName { get; set; }
public DateTime BirthDate { get; set; }
}
I have a form in a view for editing a book. The section for editing the Authors collection is in a partial view. The form fields are generated with the Html.EditorFor() method.
It works well for editing existing data. What I would like to do is to put in the Authors editing partial view multiple blank entries that if the user fills them they will be added as new items to the Authors collection.
The final view should look something like this:
http://s1.postimage.org/6g9rqfp20/image.jpg
What is the correct way to achieve this behavior?
If you are using MVC2 this is your best bet
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx#related-results
I am not sure how interested you are in using javascript libraries to get what you are looking to get done, but here is a great example of what you are trying to do: Contact Editor Example
It uses the knockouts library which allows you to work with JavaScript data binding. This also gives you a nice thick application feel on the web which users generally like.
If you are still curious about how this works with serverside, you can look at this presentation from Mix11
Good luck.
I'm writing a message board webpage. The page consists of a Topic item, then a list of Response and a form to add an additional response.
Im struggling to structure my page and viewdata classes in such a way that they are clean and allow me to take advantage for editor templates and validation attributes.
Currently I have one page to do all the above, and Im thinking my viewdata class will eventually look something like this:
public class TopicViewsData
{
[ValidateNonEmpty("Please enter some text")]
public string Title { get; set; }
[ValidateNonEmpty("Please enter some text")]
public string TopicBody { get; set; }
public IList<TopicResponseViewsData> Responses { get; set; }
public TopicResponseViewsData NewResponse { get; set; }
}
public class TopicResponseViewsData
{
[ValidateNonEmpty("Please enter some text")]
public string ResponseText{ get; set; }
}
My page is typed to a TopicViewsData, it just seems ugly that I have to have NewResponse property just so the page can have access to the validation attributes on TopicResponseViewsData. Is there a nicer way to do this?
Sounds like you are headed towards a massive and complex view, not to mention the issues you are already seeing with your model structuring. Rather than making trade offs to make what you have work I have a few recommendations on your overall view model design.
I tend to separate my models into ViewModels and FormModels. ViewModels are for displaying data and FormModels are for taking user input. Not only does this provide a clear designation of function it generally allows me to keep my FormModel properties typed to primitives, strings, and dates in addition to providing a single place for applying validation logic. While, in my ViewModels I am afforded the flexibility to use complex property types and do not have to worry about validation logic.
To make things even easier I follow Jimmy Bogard's suggestion that you should have only one view per model. By not mixing and matching models I have found my models stay focused and my views do not turn into spaghetti. To keep things tidy I name my models similarly to the Controller and View they are tied to. I might end up with a few extra models, but it is a small price to pay for a cleaner design.
I think that the Body property in the TopicViewsData model is redundant with the NewResponse property.
So your view is working with responses where each response has a body. So:
public class TopicResponseViewsData
{
[ValidateNonEmpty("Please enter some text")]
public string Body { get; set; }
}
So far so good. Next you said that you have a list of responses to show and a new response to add, so:
public class TopicViewsData
{
public IList<TopicResponseViewsData> Responses { get; set; }
public TopicResponseViewsData NewResponse { get; set; }
}
For the moment, given your description that's all I see necessary in the view model. At least model reflects your scenario description.
For a given report, the user will want to have multiple filtering options. This isn't bad when the options are enumerations, and other 'static' data types, however things can get silly fast when you need a select list that is populated by fields stored in a table in the backend.
How do you handle this scenario? I find myself constantly reshaping the View data to accommodate the additional filter fields, but it really is starting to be a bit much tracking not only the selected options, but also the options themselves...
is there not a better way?
I’m currently building out a new reporting section for one of our products at work and am dealing with this same issue. The solution I’ve come up with so far, though it hasn’t been implemented yet so this is still a work in progress, is along the lines of this.
There will be a class that will represent a report filter which will contain some basic info such as the label text and a list of option values.
public enum DisplayStyle
{
DropDown,
ListBox,
RadioList,
CheckList,
TextBox
}
public class FilterOption
{
public string Name { get; set; }
public string Value { get; set; }
public bool Selected { get; set; }
}
public class ReportFilter
{
public string Title { get; set; }
public DisplayStyle Style { get; set; }
public List<FilterOption> Options { get; set; }
}
And then my model will contain a list of these option classes that will be generated based on each report’s needs. I also have a base report class that each report will inherit from so that way I can handle building out the option lists on a per report basis and use one view to handle them all.
public class ReportModel
{
public string Name { get; set; }
public List<ReportFilter> Filters { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
Then inside my view(s) I’ll have some helper methods that will take in those option classes and build out the actual controls for me.
public static string ReportFilter(this HtmlHelper htmlHelper, DisplayStyle displayStyle, FilterOption filterOption)
{
switch (displayStyle)
{
case DisplayStyle.TextBox:
return string.Format("<input type=\"text\"{0}>", filterOption.Selected ? (" value=\"" + filterOption.Value + "\"") : string.Empty);
break;
...
}
}
My route would look like this
Reports/{reportID}/start/{startDate}/end/{endDate}/{*pathInfo}
All reports have a start and end date and then optional filters. The catchall parameter will have lists of filter values in the form of “Customer/1,4,7/Program/45,783”. So it’ll be like a key/value pair in list form. Then when the controller loads it’ll parse out those values into something more meaningful.
public static Dictionary<string, string> RouteParams(string pathInfo)
{
if (string.IsNullOrEmpty(pathInfo))
{
return new Dictionary<string, string>();
}
var values = new Dictionary<string, string>();
// split out params and add to the dictionary object
return values;
}
Then it will pass them off to the report class and validate them to make sure they’re correct for that report. Then when the options are loaded for that report anything that’s been set in the URL will be set to Selected in the ReportOption class so their state can be maintained. Then the filter list and other report data will be added to the model.
For my setup some filters will change when another filters selection changes so there will be some AJAX in here to post the data and get the updated filter options. The drilldown will work sort of like the search options at amazon or newegg when you narrow your search criteria.
I hope that all makes sense to someone beside me. And if anyone has some input on improving it I’d be happy to hear it.
You could go and retrieve the data asynchronously on the screen using jQuery and JsonResults from your MVC application, this is how we populate all of our lists and searches in our applications. I have an example of how it is done here.
This way the view data is loaded on demand, if they don't use the extra filters then they don't have to get the view data and if one selection relates to another then it's clear which set of data you need to retrieve.
Another option, though I don't like this one as much but jQuery solution may not suit you, is to have your model object for your view contain all the view data so that all you need to do is set the single model object and all the lists are loaded directly and strongly typed. This will simplify the view and the back end code because it will be more clear that for this view the only thing you need is a complete version of this model object.
For example if you had two lists for combo boxes then your model might look like:
public class MyViewMode
{
public int MyProperty { get; set; }
public string SomeString { get; set; }
List<string> ComboListA { get; set; }
List<string> ComboListB { get; set; }
}
Hope that makes sense, if not please comment and I'll expand on it.
Ad-hoc filtering on reports is indeed a tricky issue especially when you want to show a custom user interface control based on the data type, do validation, make some filters to be dependent on one another and others not, etc.
One thing I think that is worth considering is the old "build vs buy" issue here. There are specialized tools out there for ad-hoc reporting that do provide a UI for ad-hoc filters help with this such as the usual suspects Crystal Reports, Microsoft's Reporting Services, or our product ActiveReports Server. In ActiveReports Server we support cascading prompts (where available values in prompts depend on one another) and make it easy for anyone, even non-technical business users to modify the prompts (assuming they have permissions obviously). More information about using prompts in ActiveReports Server is here. ActiveReports Server is also, all managed .NET code, and provides ASP.NET controls and web services that allows you to integrate it into your web apps.
Scott Willeke
Product Manager - ActiveReports Server
GrapeCity inc.