I am writing a web application using Spring MVC. I am using annotations for the controllers, etc. Everything is working fine, except when it comes to actual links in the application (form actions, <a> tags, etc.) Current, I have this (obviously abbreviated):
//In the controller
#RequestMapping(value="/admin/listPeople", method=RequestMethod.GET)
//In the JSP
Go to People List
When I directly enter the URL like "http://localhost:8080/MyApp/admin/listPeople", the page loads correctly. However, the link above does not work. It looses the application name "MyApp".
Does anyone know if there is a way to configure Spring to throw on the application name on there?
Let me know if you need to see any of my Spring configuration. I am using the standard dispatcher servlet with a view resolver, etc.
You need to prepend context path to your links.
// somewhere on the top of your JSP
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
...
Go to People List
The c:url tag will append the context path to your URL. For example:
<c:url value="/admin/listPeople"/>
Alternately, I prefer to use relative URLs as much as possible in my Spring MVC apps as well. So if the page is at /MyApp/index, the link <a href="admin/listPeople"> will take me to the listPeople page.
This also works if you are deeper in the URL hierarchy. You can use the .. to traverse back up a level. So on the page at/MyApp/admin/people/aPerson, using <a href="../listPeople"> will like back to the list page
I prefer to use BASE tag:
<base href="${pageContext.request.scheme}://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/" />
Then, all your links can be like:
Go to People List
As i have just been trying to find the answer to this question and this is the first google result.
This can be done now using the MvcUriComponentsBuilder
This is part of the 4.0 version of Spring MVC
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.html
The method needed is fromMappingName
From the documentation :
Create a URL from the name of a Spring MVC controller method's request mapping.
The configured HandlerMethodMappingNamingStrategy determines the names of controller method request mappings at startup. By default all mappings are assigned a name based on the capital letters of the class name, followed by "#" as separator, and then the method name. For example "PC#getPerson" for a class named PersonController with method getPerson. In case the naming convention does not produce unique results, an explicit name may be assigned through the name attribute of the #RequestMapping annotation.
This is aimed primarily for use in view rendering technologies and EL expressions. The Spring URL tag library registers this method as a function called "mvcUrl".
For example, given this controller:
#RequestMapping("/people")
class PersonController {
#RequestMapping("/{id}")
public HttpEntity getPerson(#PathVariable String id) { ... }
}
A JSP can prepare a URL to the controller method as follows:
<%# taglib uri="http://www.springframework.org/tags" prefix="s" %>
Get Person
I usually configure tomcat to use context root of "/" or deploy the war as ROOT.war. Either way the war name does not become part of the URL.
You could use a servletRelativeAction. I'm not sure what versions this is available in (I'm using 4.0.x currently) and I haven't seen much documentation on this, but if you look at the code backing the spring form you can probably guess. Just make sure the path you pass it starts with a "/".
Example:
<form:form class="form-horizontal" name="form" servletRelativeAction="/j_spring_security_check" method="POST">
See org.springframework.web.servlet.tags.form.FormTag:
protected String resolveAction() throws JspException {
String action = getAction();
String servletRelativeAction = getServletRelativeAction();
if (StringUtils.hasText(action)) {
action = getDisplayString(evaluate(ACTION_ATTRIBUTE, action));
return processAction(action);
}
else if (StringUtils.hasText(servletRelativeAction)) {
String pathToServlet = getRequestContext().getPathToServlet();
if (servletRelativeAction.startsWith("/") && !servletRelativeAction.startsWith(getRequestContext().getContextPath())) {
servletRelativeAction = pathToServlet + servletRelativeAction;
}
servletRelativeAction = getDisplayString(evaluate(ACTION_ATTRIBUTE, servletRelativeAction));
return processAction(servletRelativeAction);
}
else {
String requestUri = getRequestContext().getRequestUri();
ServletResponse response = this.pageContext.getResponse();
if (response instanceof HttpServletResponse) {
requestUri = ((HttpServletResponse) response).encodeURL(requestUri);
String queryString = getRequestContext().getQueryString();
if (StringUtils.hasText(queryString)) {
requestUri += "?" + HtmlUtils.htmlEscape(queryString);
}
}
if (StringUtils.hasText(requestUri)) {
return processAction(requestUri);
}
else {
throw new IllegalArgumentException("Attribute 'action' is required. " +
"Attempted to resolve against current request URI but request URI was null.");
}
}
}
Since it's been some years I thought I'd chip in for others looking for this. If you are using annotations and have a controller action like this for instance:
#RequestMapping("/new") //<--- relative url
public ModelAndView newConsultant() {
ModelAndView mv = new ModelAndView("new_consultant");
try {
List<Consultant> list = ConsultantDAO.getConsultants();
mv.addObject("consultants", list);
} catch (Exception e) {
e.printStackTrace();
}
return mv;
}
in your .jsp (view) you add this directive
<%#taglib uri="http://www.springframework.org/tags" prefix="spring"%>
and simply use
<spring:url value="/new" var="url" htmlEscape="true"/>
New consultant
where
value's value should match #RequestMapping's argument in the controller action and
var's value is the name of the variable you use for href
HIH
Related
I am replacing a Project built using ASP.NET WebForms and I need to replace the .ashx Generic Handlers - but I need to keep the page names so an app that has these URIs hardcoded does not require updating.
I know how to deal with the logic, that is not the problem. The problem is that these pages are referenced by an app that I do not want to update, so I need to be able to use URIs that point to pages ending in .ashx.
I have tried everything I can think of. I had hoped to just use the #page directive as shown below:
#page "/mygenerichandler.ashx"
Unfortunately, that does not work. If it did, I would be all set.
I have seen pages telling me to handle the .ashx as a sort of parameter:
#page "/mygenerichandler/{ashx}" (and variations of this, none work)
This does not work.
I have tried just naming the pages with the .ashx extension. This does not work.
I do not want to have to update the apps that have the URLs embedded in them, but it is looking more and more like that is my only option.
Is there any way to accept a page request in Blazor to a page that is named something like "mygenerichandler.ashx"?
I figured it out. I am using the Middleware Pattern, and it turns out that this will execute early in the pipeline and allow me to inspect the URL for the .ashx extension and then route accordingly. I should be able to return a response from this point - I still have to implement that code, but it is not directly germane to this question so I will not cover it here.
public class HandlerTrapper
{
private readonly RequestDelegate _next;
public string? AccountID { get; set; }
public HandlerTrapper(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext) //, [FromQuery(Name = "AccountID")] string accountId
{
string? page = httpContext.Request.Path.Value?.Replace(#"/", "");
Console.WriteLine("Page Name is {0}, AccountID = {1}", page, AccountID);
if(page==null || !page.Contains(".ashx"))
return _next(httpContext);
AccountID = httpContext.Request.Query["AccountID"];
switch (page)
{
case "GetAmzRefreshToken":
break;
}
return _next(httpContext);
}
private
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class HandlerTrapperExtensions
{
public static IApplicationBuilder UseHandlerTrapper(this IApplicationBuilder builder)
{
return builder.UseMiddleware<HandlerTrapper>();
}
}
This is called as shown here in Program.cs:
app.UseHandlerTrapper();
I am pretty sure I can just return a Response from here and after implementing the code that does the work based on the incoming legacy page name, I should have a replacement for my .ashx Generic Handlers.
There is an even better solution which I implemented in my code. The WebApplication class has a UrlReWriter method that solves this problem quite elegantly when used in conjunction with the Controller Routing.
I added these lines to my Program.cs file - I placed them before the UseHttpRedirection and the UseRouting calls.:
RewriteOptions urlOptions = new RewriteOptions().AddRewrite(#"^(.*).ashx$", "api/$1", false);
urlOptions.AddRewrite(#"^(.*).inf$", "api/ComputerInfo", false);
app.UseRewriter(urlOptions);
That resolved the issue for both of the file type patterns I needed to handle, and I can add more if need be.
I've recently moved from MVC5 over to .NET Core 2.1 (MVC). Can anyone help me with this please.
I have my ApplicationUser and I've extended the model/table to store the user's FirstName.
In the View, I want to be able to output the current user firstname value.
User in the view is a ClaimsPrincipal so I need to go off to the DB to grab the value I need or access UserManager to get it.
Now, I know I can get that in the controller but I don't want to have to create a JQuery call to grab it every time I need it.
What I do want is to be able to access it server side, ideally via a static helper class.
In the MVC5 I'd have a helper to do the job no problem. Something like this for example:
public static string GetCurrentUserFirstName()
{
string _usrRef = HttpContext.Current.User.Identity.GetUserId();
var user = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>().FindById(_usrRef);
return user.FirstName;
}
However, .NET Core doesn't work that way.
In a controller I could say:
var user = await _userManager.GetUserAsync(User);
string firstName = user.FirstName;
or I could go off to the DB via a call using Dapper w/ my connection string.
I can't inject the UserManager or ConnectionStrings into the helper via the constructor as it is static.
Is there a way to access either of those in this static helper?
It's the little changes that get you the most!
Thanks to #Kirk Larkin - I've found the solution.
I have to admit, it feels a little more convoluted having to pass things around to gain access to them but this is a good, working solution.
The View:
#using Microsoft.AspNetCore.Identity
#using MyApplication.Helpers
#inject UserManager<ApplicationUser> UserManager
<div>
#await MyHelper.GetLoggedInUserFirstName(UserManager, User)
</div>
The MyHelper file:
public static async Task<string> GetLoggedInUserFirstName(UserManager<ApplicationUser> userManager, ClaimsPrincipal user)
{
string output = "";
try
{
var currentUser = await userManager.GetUserAsync(user);
if(currentUser!=null)
{
output = currentUser.FirstName ?? currentUser.Email;
}
}
catch(Exception e) { }
return output;
}
I'm trying out building a web API with MVC 6. But when one of my controller methods throws an error, the content of the response is a really nicely formatted HTML page that would be very informative were this an MVC app. But since this is an API, I'd rather have some JSON returned instead.
Note: My setup is super basic right now, just setting:
app.UseStaticFiles();
app.UseIdentity();
// Add MVC to the request pipeline.
app.UseMvc();
I want to set this up universally. Is there a "right/best" way to set this up in MVC 6 for an API?
Thanks...
One way to achieve your scenario is to write an ExceptionFilter and in that capture the necessary details and set the Result to be a JsonResult.
// Here I am creating an attribute so that you can use it on specific controllers/actions if you want to.
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
var exception = context.Exception;
context.Result = new JsonResult(/*Your POCO type having necessary details*/)
{
StatusCode = (int)HttpStatusCode.InternalServerError
};
}
}
You can add this exception filter to be applicable to all controllers.
Example:
app.UseServices(services =>
{
services.AddMvc();
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new CustomExceptionFilterAttribute());
});
.....
}
Note that this solution does not cover all scenarios...for example, when an exception is thrown while writing the response by a formatter.
I've a helper like this, I created this using raw HTML inside as follows:
private static readonly Core Db = new Core();
// Main menu
public static MvcHtmlString MainMenu()
{
IQueryable<Page> primaryPages = Db.Pages.Where(p => p.IsItShowInMenu);
var sb = new StringBuilder();
sb.Clear();
string pagecode = Convert.ToString(HttpContext.Current.Request.RequestContext.RouteData.Values["url"]);
sb.Append("<div id=\"Logo\">");
sb.Append("<span id=\"Logo_Text\">Dr. Shreekumar</span> <span id=\"Logo_Sub_Text\">Obstetrician & Gynecologist</span>");
sb.Append("</div>");
sb.Append("<div id=\"Primary_Menu\">");
sb.Append("<ul>");
foreach (Page page in primaryPages)
{
if (page.PageCode != "Home")
{
Page currentPage = Db.Pages.SingleOrDefault(p => p.PageCode == pagecode);
if (currentPage != null)
{
Page parentPage = Db.Pages.Find(currentPage.ParentId);
if (parentPage != null)
{
sb.AppendFormat((page.PageCode == parentPage.PageCode ||
page.PageCode == currentPage.PageCode)
? "<li class=\"active\">{1}</li>"
: "<li>{1}</li>", page.PageCode,
page.Name.Trim());
}
else
{
sb.AppendFormat("<li>{1}</li>", page.PageCode,page.Name);
}
}
else
{
sb.AppendFormat("<li>{1}</li>", page.PageCode, page.Name);
}
}
}
sb.Append("</ul>");
sb.Append("</div>");
return new MvcHtmlString(sb.ToString());
}
Can anybody suggest me that how can I convert this using MVC HTML helpers (helpers for anchor, list (li), div etc)
It is an important part of your role as the architect of your application to define what will be generated by helpers and what not, as it depends on what is repeated where and how often in your code. I am not going to tell you what to build helpers for because that depends on the architecture of your whole application. To help you make the decision, however, consider the two general types of helpers you can build: global and local.
Global helpers are for chunks of code which are often repeated across your site, possibly with a few minor changes that can be handled by passing in different parameters. Local helpers do the same job, but are local to a given page. A page which has a repeating segment of code that isn't really found anywhere else should implement a local helper. Now then...
Global helpers: Create a new static class to contain your helpers. Then, create static methods inside the container class that look like this:
public static MvcHtmlString MyHelper(this HtmlHelper helper, (the rest of your arguments here))
{
// Create your HTML string.
return MvcHtmlString.Create(your string);
}
What this does is create an extension method on the Html helper class which will allow you to access your helpers with the standard Html. syntax. Note that you will have to include the namespace of this class in any files where you want to use your custom helpers.
Local helpers: The other way to do helpers works when you want them to be local to a single view. Perhaps you have a block of code in a view that is being repeated over and over again. You can use the following syntax;
#helper MyHelper()
{
// Create a string
#MvcHtmlString.Create(your string here);
}
You can then output this onto your page using:
#MyHelper()
The reason why we are always creating MvcHtmlString objects is because as a security feature built into MVC, outputted strings are encoded to appear as they look in text on the page. That means that a < will be encoded so that you actually see a "<" on the page. It won't by default start an HTML tag.
To get around this, we use the MvcHtmlString class, which bypasses this security feature and allows us to output HTML directly to the page.
I suggest you move all this logic into a separate Section as it is a Menu that is being rendered.
Instead of building the HTML from the code, it is cleaner and a lot more convenient to build it using Razor's helpers. Refer to this as well as this article from Scott Gu on how to render sections to get a quick starting guide.
Consider using Helper methods such as
#Html.DropDownListFor() or
#Html.DropDownList()
I have developed a simple mechanism for my mvc website to pull in html via jquery which then populates a specified div. All is well and it looks cool.
My problem is that i'm now creating html markup inside of my controller (Which is very easy to do in VB.net btw) I'd rather not mix up the sepparation of concerns.
Is it possible to use a custom 'MVC View User Control' to suit this need? Can I create an instance of a control, pass in the model data and render to html? It would then be a simple matter of rendering and passing back to the calling browser.
This is a solution that is working with ASP.Net MVC 1.0 (many that claim to work with beta 3 don't work with 1.0), doesn't suffer of the 'Server cannot set content type after HTTP headers have been sent' problem and can be called from within a controller (not only a view):
/// <summary>
/// Render a view into a string. It's a hack, it may fail badly.
/// </summary>
/// <param name="name">Name of the view, that is, its path.</param>
/// <param name="data">Data to pass to the view, a model or something like that.</param>
/// <returns>A string with the (HTML of) view.</returns>
public static string RenderPartialToString(string controlName, object viewData) {
ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() };
viewPage.Url = GetBogusUrlHelper();
viewPage.ViewData = new ViewDataDictionary(viewData);
viewPage.Controls.Add(viewPage.LoadControl(controlName));
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb)) {
using (HtmlTextWriter tw = new HtmlTextWriter(sw)) {
viewPage.RenderControl(tw);
}
}
return sb.ToString();
}
public static UrlHelper GetBogusUrlHelper() {
var httpContext = HttpContext.Current;
if (httpContext == null) {
var request = new HttpRequest("/", Config.Url.ToString(), "");
var response = new HttpResponse(new StringWriter());
httpContext = new HttpContext(request, response);
}
var httpContextBase = new HttpContextWrapper(httpContext);
var routeData = new RouteData();
var requestContext = new RequestContext(httpContextBase, routeData);
return new UrlHelper(requestContext);
}
It's a static method you can drop somewhere you find it convenient. You can call it this way:
string view = RenderPartialToString("~/Views/Controller/AView.ascx", someModelObject);
I put together a rough framework which allows you to render views to a string from a controller method in MVC Beta. This should help solve this limitation for now.
Additionally, I also put together a Rails-like RJS javascript generating framework for MVC Beta.
Check it out at http://www.brightmix.com/blog/how-to-renderpartial-to-string-in-asp-net-mvc and let me know what you think.
You would create your action like this:
public PartialViewResult LoginForm()
{
var model = // get model data from somewhere
return PartialView(model);
}
And the action would return the rendered partial view to your jquery response.
Your jquery could look something like this:
$('#targetdiv').load('/MyController/LoginForm',function(){alert('complete!');});
You should use jquery to populate your divs (and create new html elements if needed), and Json serialization for ActionResult.
Other way is to use jquery to call some controller/action, but instead json use regular View (aspx or ascx, webforms view engine) for rendering content, and with jquery just inject that html to some div. This is half way to UpdatePanels from asp.net ajax...
I would probably go with first method, with json, where you have little more job to do, but it's much more "optimized", because you don't transfer whole html over the wire, there are just serialized objects. It's the way that "big ones" (gmail, g docs, hotmail,..) do it - lot of JS code that manipulates with UI.
If you don't need ajax, then you basically have two ways of calling partial views:
html.renderpartial("name of ascx")
html.RenderAction(x=>x.ActionName) from Microsoft.web.mvc (mvc futures)
After much digging in google i have found the answer.
You can not get easy access to the html outputted by the view.
http://ayende.com/Blog/archive/2008/11/11/another-asp.net-mvc-bug-rendering-views-to-different-output-source.aspx
I've done something similar for an app I'm working on. I have partial views returning rendered content can be called using their REST path or using:
<% Html.RenderAction("Action", "Controller"); %>
Then in my actual display HTML I have a DIV which is filled from jQuery:
<div class="onload">/controller/action</div>
The jQuery looks like this:
<script type="text/javascript">
$.ajaxSetup({ cache: false });
$(document).ready(function () {
$('div.onload').each(function () {
var source = $(this).html();
if (source != "") {
$(this).load(source);
}
});
});
</script>
This scans for all DIV that match the "onload" class and reads the REST path from their content. It then does a jQuery.load on that REST path and populates the DIV with the result.
Sorry gotta go catch my ride home. Let me know if you want me to elaborate more.
You have several options.
Create a MVC View User Control and action handler in your controller for the view. To render the view use
<% Html.RenderPartial("MyControl") %>
In this case your action handler will need to pass the model data to the view
public ActionResult MyControl ()
{
// get modelData
render View (modelData);
}
Your other option is to pass the model data from the parent page. In this case you do not need an action handler and the model type is the same as the parent:
<% Html.RenderPartial("MyControl", ViewData.Model) %>
If your user control has it's own data type you can also construct it within the page
In MyControl.ascx.cs:
public class MyControlViewData
{
public string Name { get; set; }
public string Email { get; set; }
}
public partial class MyControl : System.Web.Mvc.ViewUserControl <MyControlViewData>
{
}
And in your page you can initialize your control's data model:
<% Html.RenderPartial("MyControl", new MyControlViewData ()
{
Name= ViewData.Model.FirstName,
Email = ViewData.Model.Email,
});
%>
In rails this is called rendering a partial view, and you do it with render :partial => 'yourfilename'. I believe ASP.NET MVC has a similar RenderPartial method, but I can't find the official docs for MVC to confirm or deny such a thing.
it is very simple you just have to create a strongly typed partial view(or user control) then in your cotroller something like this:
public PartialViewResult yourpartialviewresult()
{
var yourModel
return PartialView("yourPartialView", yourModel);
}
then you can use JQuery to perform the request whener you want:
$.ajax({
type: 'GET',
url: '/home/yourpartialviewresult',
dataType: 'html', //be sure to use html dataType
contentType: 'application/json; charset=utf-8',
success: function(data){
$(container).html(data);
},
complete: function(){ }
});
I found this one line code to work perfectly. orderModel being my model object. In my case I had a helper method in which I had to merge a partial view's html.
System.Web.Mvc.Html.PartialExtensions.Partial(html, "~/Views/Orders/OrdersPartialView.cshtml", orderModel).ToString();