How to have multiple HTML static pages on a ASP.NET MVC project using the Layout page? - html

On my MVC project I have to incorporate 40 static pages.
I want these pages to use the Layout page.
What is the best way to do that?
I know this question was asked before but I didn't find any good answer.
Any advise?

I don't relly know ASP, but I try to give a generic answer.
So I think if you have a lot of similar static pages, somehow you could make a controller action that handles all these pages. For example the action gets the name of the page as a path variable in the URL, and return the view according to that.
But if that is not possible in the language you are using, you can just make simple separate actions for these pages. Maybe you could group the related ones into the same controller, so you would have a few controllers that handle these pages, and they are not stuffed in one controller.

Basically the solution is very simple, you have to create views for you static HTML (cshtml), then you should add a Route to your Route.Config like this:
routes.MapRoute(
"OrdeForm",
"OrderForm/{file}",
new { controller = "MyController", action = "Page", file} = "" }
);
Where "File" is a dynamic parameter that gets the View name from the URL and renders the right View.
The global controller should be something like this:
public class OrderFormController : Controller
{
public ActionResult Index(string file)
{
return View(file);
}
}
That works perfectly!
Thank you #Erik Philips for the excellant answer!

Related

MVC6 Routing Issue

I'm new to MVC coding, and have been at this issue for a couple days now. I'm having trouble setting up multiple routing schemes, and having them work as intended. Here is what I've got.
Framework
Products/Info.cshtml
Products/Edit.cshtml
Model
ProductCategory.Id
ProductCategory.CategoryName
What I'm wanting to do is be able to have 2 different routing schemes in place
Products/Edit/Id
Products/Info/CategoryName
So here is how I'm structuring the tags in the documents
For Products/Edit/Id
< a asp-controller="Products" asp-action="Edit" asp-route-id="#item.Id">Edit< /a>
For Products/Info/CategoryName
< a asp-controller="Products" asp-action="Info" asp-route-category="#item.CategoryName">#item.CategoryName< /a>
So the thing is, this will actually work, functionally, but my hyperlinks for the Products/Info/CategoryName get rendered as query strings rather than the more user friendly version, for instance one category is "Fireplaces", so my links for Info become
Products/Info?category=Fireplaces
instead of what I'm wanting
Products/Info/Fireplaces
How can I configure my routes so that the Controller/Action/Parameter call works for both? I've already tried adding specific routes to app.UseMvc(), and again they work functionally, but the Info links still render out as query strings.
Ok, finally got to the bottom of it. Rather than trying to define routes the old way, with app.UseMvc(), I was able to use the new DataAnnotations in the Controller class to define the route, which resulted in creating user friendly links like I wanted, rather than the query string links. So for my Info() method in my controller class, I changed to look like
[HttpGet]
[ActionName("Info")]
[Route("Products/Info/{category}")]
public IActionResult Info(string category)
{
.....
return View(productCategory);
}

Get an absolute link from a relative one in Freemarker

I'm creating a site using Magnolia - CMS. Now I am implementing a blog page. On each blog page, there are several share buttons. Now I'm busy implementing the twittershare button. Here I am going to use the twitter cards. For that, I need to provide the URL of an image in a metatag. Main problem: I retreive my image like this: ${damfn.getAssetLink(content.blogImage)}. This only returns a relative path to my resource. Is there a quick way (in freemarker), that will convert tis to an absolute link?
Many thanks in advance!
usually you define magnolia.default.base.url in the magnolia.properties.
then you can retrieve it with Components.getComponent(ServerConfiguration.class).getDefaultBaseUrl()
now you have to install the service into freemarker. you can do that by adding installer-tasks into the renderers on startup. you do that in your module-version-handler. there you overwrite the getStartupTasks(...), something like this:
#Override
protected List<Task> getStartupTasks(InstallContext installContext) {
final List<Task> tasks = new ArrayList<>();
tasks.add(new InstallRendererContextAttributeTask("rendering", "freemarker", "serverConf", ServerConfiguration.class.getName()));
tasks.add(new InstallRendererContextAttributeTask("site", "site", "serverConf", ServerConfiguration.class.getName()));
return tasks;
}
now you can call in freemarker:
"${serverConf.defaultBaseUrl}/${ctx.contextPath}/${damfn.getAssetLink(content.blogImage)}"
checkout if the slashes are necesarry and make sure that defaultBaseUrl is set properly in your magnolia configuration ("/server/...")
edit: there should be an easier by calling the current request in freemarker ${Request} so it could be something like "${Request.domain}/${ctx.contextPath}/${damfn.getAssetLink(content.blogImage)}" without injecting the serverConfiguration into the renderer

Create Dynamic View with static HTML in MVC

I have been researching dynamic content for MVC views and partial views but have not successfully found an architecture to fit my needs.
Basically I am required to create a landing page based on parameters pass by the URL.
For basics
http://mydns.com/myconroller/myview/?landingpage=Param1
The controller will need to find the HTML that will be used to create the view.
The view is going to be different based on the landing page.
(for the sake of the question, I am using landingpage as an example)
My goal is to be able to deploy a Landing page and based on the URL use that HTML Landing page in the view based on the landingpage parameter that is passed.
There are other views that are working currently in the controller. I am trying to add functionality to be able to add a new one time page without having to recompile.
I have searched through various ideas on how to load dynamic views but cannot seem to find a solution that fits this need based on what I have read.
I can possibly RedirectToAction but I am still in the dark on where to deploy and I am getting several problems with Razor as it is not in the shared directory and then I am stuck with deployment issues as I want to organize the landing pages differently than I am organizing the views.
Solution:
I decided to take a different approach and use the ContentResult Action in the controller. I still have the Main View and I use the HTML extensions to render the HTML pages that I have deployed in my customer's directory.
#{
Html.RenderAction("LandingPageContent", "Controller", Model);
}
Then in the controller I load the HTML directly and return the ContentResult
public ContentResult LandingPageContent(object model, FormCollection collection)
{
MySRCHelper helper = new MySRCHelper();
ContentVariables variables = helper.getContentSRC(model.EntryCode);
model.ContentSRC = variables.LandingPageSRC;
return Content(System.IO.File.ReadAllText(Server.MapPath(model.ContentSRC)));
}
I can then configure the path to the raw HTML file to be used and it will be loaded into the View. The View can then house all of the paths to load jQuery, CSS and other necessary javascript to integrate with the raw HTML and allow me to deploy the HTML files into any directory structure that I want. The configuration XML file allows me to find XML elements and use those values for any HTML that I am looking for, like a welcome and thank you page. The helper object will open the XML and find the configuration based on the parameters passed to the View.
<ContentLandingItem entrycode="1" customerID="Cutomer1">
<ContentLandingPageSRC>~/Customers/Customer1/Customer1Landing.htm</ContentLandingPageSRC>
<ContentThankyouSRC>~/Content/Default/GenericThankyou.htm</ContentThankyouSRC>
</ContentLandingItem>
<ContentLandingItem entrycode="2" customerID="Cutomer2">
<ContentLandingPageSRC>~/Customers/Customer2/Customer2Landing.htm</ContentLandingPageSRC>
<ContentThankyouSRC>~/Customers/Customer2/Customer2Thankyou.htm</ContentThankyouSRC>
</ContentLandingItem>
The view still performs its duties and works independently on it own letting the raw HTML decorate the View. The model is still intact and can be used as I wish. The FormCollection is there in case a form submit posts the values to the view and provides some things that I omitted from this question as it did not pertain to this subject.
I don't want to answer my own question and I found the pieces that helped me on another site, so I am putting what I did here in case anyone needs this functionality.
This sounds like using the you can inherit from the virtual path provider view engine and decide based on the URL parameters (or other) which view to return. Some example that you can adjust to your needs:
public class CustomViewEngine : VirtualPathProviderViewEngine
{
public MyViewEngine()
{
this.ViewLocationFormats = new string[] { "~/Views/{1}/{2}.mytheme ", "~/Views/Shared/{2}.mytheme" };
this.PartialViewLocationFormats = new string[] { "~/Views/{1}/{2}.mytheme ", "~/Views/Shared/{2}. mytheme " };
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
var physicalpath = controllerContext.HttpContext.Server.MapPath(partialPath);
return new RazorView(controllerContext, physicalpath);
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
var physicalpath = controllerContext.HttpContext.Server.MapPath(viewPath);
return new RazorView(controllerContext, physicalpath);
}
}
In there you can return a RazorView or WebFormView and set your desired path for the view to use.

Is there an example on using Razor to generate a static HTML page?

I want to generate a static HTML page by RAZOR, basically by using includes of partial sub pages.
I have tried T4 as well and do look for an alternative: see here and here
This answer says it is possible - but no concrete example
I have installed Razor generator because I thought this is the way to go, but I do not get how to generate static HTML with this.
Best would be a complete extension which behaves like the T4 concept, but allows me to use the RAZOR syntax and HTML formatting (the formatting issue is basically the reasons why I am not using T4).
If you are trying to take a Razor view and compile it and generate the HTML then you can use something like this.
public static string RenderViewToString(string viewPath, object model, ControllerContext context)
{
var viewEngineResult = ViewEngines.Engines.FindView(context, viewPath, null);
var view = viewEngineResult.View;
context.Controller.ViewData.Model = model;
string result = String.Empty;
using (var sw = new StringWriter())
{
var ctx = new ViewContext(context, view,
context.Controller.ViewData,
context.Controller.TempData,
sw);
view.Render(ctx, sw);
result = sw.ToString();
}
return result;
}
Or outside of ControllerContext http://razorengine.codeplex.com/
The current version of Razor Generator has the "Generator" option which when used with the "MvcHelper" generator produces a static method for the helpers too.
For example, add this line at the top of your CSHTML file (with the Custom Tool Visual Studio property set to RazorGenerator of course):
#* Generator: MvcHelper, GeneratePrettyNames : true *#
The pretty names option is not strictly necessary but is something I feel should be default, to avoid those crazy long class names with underscores :-)
As you may know already, the main benefit of this method is you can share your helpers in separate assemblies. That is why I use Razor Generator in the first place.
Even within the same assembly, you could now leave your code outside App_Code folder. However that is not the best practice (at least for security) and the Visual Studio designer gets confused. It thinks the method is still not static, but it isn't and works fine.
I'm prototyping my helpers in the App_Code folder of the same site/assembly for speed then copying them to shared components when they're tested. The reason I needed this solution was to create generic Bootstrap helpers without hand-coding every piece of HTML in a HtmlHelper, i.e. used together with this solution from #chrismilleruk.
I guess later I may have to convert the CSHTML helpers to a hand-coded HtmlHelper for speed. But to start with see a great development speed increase at the beginning, from the ability to copy and paste blocks of HTML code I want to automate, then perfect and debug them quickly in the same format/editor.

Model Validation without the ValidationSummary?

I have a LoginModel for my Login Action, but I'm wanting to use just HTML.
Example...
public class LoginModel
{
[Required]
public string Email { get;set; }
}
in my HTML, I have
<input type="text" value="" name="Email">
This is because I'm going to be storing my HTML in my database, problem I'm having is, how do I get model validation without using Html.ValidationSummary()?
I was hoping I could just do <div class="validation-summary-errors"></div>
As this is what is in the HTML, but does not work..
Ideas?
Regardless of where you store your HTML the validation is done on the client side. There are various posts on how to use the virtual path provider to store your views somewhere else (DB) and then validation should still work fine. I think I'm missing why it's not working for you though so I have to imagine you aren't using the path provider to find your views.
Edit
Seems you want to inject messages into a Div. This wont happen automaticaly unless you work some magic in the path provider. Use your own helper method in the view to avoid hacks or just use what's provided by default. If you really want to do it render your view in your controlllet and search for your Div pattern to replace.
custom ValidationForMessage helper removing css element
Note Darin's method
var expression = ExpressionHelper.GetExpressionText(ex);
var modelName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(expression);
var modelState = htmlHelper.ViewData.ModelState[modelName];
without access to ViewContext in your controller you can only render your html for your View. However, somewhere in your view you need (as far as I can tell) a helper method to stick your error collection into ViewData.
Your Virtual Path Provider may have to inject this helper method into your view text so it is there for Razor to parse. Actually - duh. This may be much easier. Your provider may be able to just simply read your html from the database, find the div, and inject the #Html.ValidationSummary into that div. I believe this would work. Why not just put the validation summary in there though if its going to end up there in the end anyways (essentially)