How does Url.Action work Asp.net MVC? - asp.net

This is somewhat related to another question I've asked but I figure why not ask it seperately.
If I were to place something like the following in a view
<td><img src='<%= Url.Action( "DisplayImage" , "User" , new { id = item.id} ) %>' alt="" /></td>
Is it supposed to display this?
<td>
<img src='/User.mvc/DisplayImage?id=U00915441' alt="" />
</td>
Or would the value of the src-attribute actually be replaced with the results of the UserController GetImage Action?

It will construct the path to the action, returning a url, not the results of executing the action.
The results will be:
<td>
<img src='/User.mvc/DisplayImage?id=U00915441' alt="" />
</td>
Example code. assumes your user model has the image stored in a byte array. If you are using LINQ and the property is a Binary, then use the ToArray() method to convert it to a byte array. Note the attributes which will require that the user be logged in and using a GET request.
[Authorize]
[AcceptVerbs( HttpVerbs.Get )]
public ActionResult DisplayImage( string id )
{
var user = ...get user from database...
return File( user.Image, "image/jpeg" );
}
}

Related

ASP.NET Razor: Send variable as parameter

My view contains the following table definition:
<table>
<thead>
<th>Title</th>
<th>Artist</th>
<th>Genre</th>
<th>Price</th>
</thead>
#foreach (var album in Model)
{
<tr>
<td>#album.Title</td>
<td>
#{
foreach (var artist in ViewBag.Artists)
{
if (artist.ArtistID == album.ArtistID)
{ #artist.Name }
}
}
</td>
<td>
#{
foreach (var genre in ViewBag.Genres)
{
if (genre.GenreID == album.GenreID)
{ #genre.Name }
}
}
</td>
<td>#album.Price</td>
<td>
<a asp-action="Details" asp-controller="Albums">Details </a>
<a asp-action="Edit" asp-controller="Albums">Edit </a>
<a asp-action="Delete" asp-controller="Albums">Delete</a>
</td>
</tr>
}
</table>
The Details, Edit, and Delete options in the final column need to be keyed to the AlbumID property of the album variable, in order to ensure that the redirect operates on the proper album. I had thought the parameter for this might be asp-parameter, much like the action is set by asp-action, but this does not appear to exist.
What is the proper method to pass a variable as a URL parameter (for instance, /Albums/Details/var), and what name is used to retrieve this on the other side?
Shyju's answer deals with passing the parameter; my attempts at retrieving the parameter thus far have been as follows:
<%=Url.RequestContext.RouteData.Values["id"]%> - Fails to load, invalid character <.
ViewContext.RouteData.Values["id"] - Fails to load, cannot compare int and object using ==.
RouteData.Values["id"] - Compilation error, name does not exist in current context.
When using link tag helper, You can pass additional information to the action method using the asp-route-[paramName] attribute. For example, if you want to pass the album id to the id parameter of your details action method, you can do this
<a asp-action="Details" asp-controller="Albums" asp-route-id="#album.ID">Details </a>
This will generate the markup like below
<a href='/Albums/Details/101'>Details</a>
Where 101 will be replaced by an actual Album Id value.
Assuming your Details action method has a parameter named id
public ActionResult Details(int id)
{
// to do : Get the album using the id and send something to the view
}

Spring MVC update without redundant code?

I'm working on a Spring MVC controller and views to implement CRUD operations for a simple object named Partner. The update operation troubles me. It seems like I need to write several lines of code manually that I expected Spring MVC would take care of automatically. Is there a best practice that I'm missing here?
Here's my view:
<%# include file="include.jsp"%>
<form:form commandName="partner">
<input type="hidden" name="_method" value="PUT" />
<table>
<tr>
<td>Id:</td>
<td><form:input path="id" disabled="true" /></td>
</tr>
<tr>
<td>Name:</td>
<td><form:input path="name" /></td>
</tr>
<tr>
<td>Logo:</td>
<td><form:input path="logo" /></td>
</tr>
<tr>
<td>On-screen text:</td>
<td><form:textarea path="onScreenText" /></td>
</tr>
<tr>
<td colspan="2"><input type="submit" value="Save Changes" /></td>
</tr>
</table>
</form:form>
And here's my controller method for the update operation:
#RequestMapping(value="/partner/{partnerId}", method=RequestMethod.PUT)
public ModelAndView updatePartner(#ModelAttribute Partner partner, #PathVariable int partnerId) {
EntityManager entityManager = DatabaseHelper.getEntityManager();
try {
Partner partnerToUpdate = entityManager.find(Partner.class, partnerId);
entityManager.getTransaction().begin();
partnerToUpdate.setId(partnerId);
partnerToUpdate.setName(partner.getName());
partnerToUpdate.setLogo(partner.getLogo());
partnerToUpdate.setOnScreenText(partner.getOnScreenText());
entityManager.persist(partnerToUpdate);
entityManager.getTransaction().commit();
}
finally {
entityManager.close();
}
return new ModelAndView("redirect:/partner");
}
The lines of code that trouble me are:
Partner partnerToUpdate = entityManager.find(Partner.class, partnerId);
partnerToUpdate.setId(partnerId);
partnerToUpdate.setName(partner.getName());
partnerToUpdate.setLogo(partner.getLogo());
partnerToUpdate.setOnScreenText(partner.getOnScreenText());
Do I really need to look up the existing Partner in the database and explicitly update each field of that object? I already have a Partner object with all the right values. Is there no way to store that object directly to the database?
I've already looked at Spring MVC CRUD controller best pactice, but that didn't quite answer my question.
As one possible suggestion, you could lookup the existing Partner object as part of model creation so that this model instance backs the form and Spring binds the fields directly to it. One way to achieve this would be to create an explicit method in the controller responsible for creating the model.
For example:
#ModelAttribute("partner")
public Partner createModel(#PathVariable int partnerId) {
Partner partner = entityManager.find(Partner.class, partnerId);
return partner;
}
And then you could remove the copying from the updatePartner method - because Spring will already have bound the form fields directly to the loaded Partner object.
#RequestMapping(value="/partner/{partnerId}", method=RequestMethod.PUT)
public ModelAndView updatePartner(#ModelAttribute("partner") Partner partner) {
EntityManager entityManager = DatabaseHelper.getEntityManager();
try {
entityManager.getTransaction().begin();
entityManager.persist(partner);
entityManager.getTransaction().commit();
}
finally {
entityManager.close();
}
return new ModelAndView("redirect:/partner");
}
One caveat - because the createModel method would get called for every request to the controller (not just updatePartner), the partnerId path variable would need to be present in all requests.
There's a post here which goes over a solution to that issue.
You can use merge to update the desired values, something like:
#RequestMapping(value="/partner/{partnerId}", method=RequestMethod.PUT)
public ModelAndView updatePartner(#ModelAttribute Partner partner, #PathVariable int partnerId) {
EntityManager entityManager = DatabaseHelper.getEntityManager();
try {
entityManager.getTransaction().begin();
partner.setId(partnerId);
entityManager.merge(partner);
entityManager.getTransaction().commit();
}
finally {
entityManager.close();
}
return new ModelAndView("redirect:/partner");
}
Also, I recommend You to use the DAO Pattern and Spring Transaction Support with #Transactional and #Repository

asp.net mvc 3, dynamic array

I am a beginner in ASP.Net MVC 3
I will make a dynamic array initially must show me the first ten elements, and when I click view more displays all array elements
here's what I did:
<table>
#foreach (var tweet in Model)
{
<tr>
<td>
<img alt="" src="#tweet.ProfileImageUrl" />
<br />
<input id="rowIDs" type="checkbox" />
</td>
<td>
<strong>#tweet.Name</strong>
<br />
Friends: <strong>#tweet.FriendsCount</strong>
</td>
</tr>
}
</table>
thank you in advance
You have to put 10 items in the controller,
return View(array.Take(10).Skip(page));
Do not use the button anymore. Use the pager.
You need to peredovat variable Pag.
The easiest way(on my opinion) is to create a anchor to the page, itself, with a query string.
Your View must have an anchor like this:
All Comments
And relative controller(HttpGet, not HttpPost(if it has any)) must be something like this:
public ViewResult List(bool fullComment=false)
{
if (fullComment)
return View(dbContext.EntityList.ToList());
else
return View(dbContext.EntityList.Take(5).ToList());
}
Note: if the page has querystring already, in creating anchor link, in view, you must pay attention to this.

Getting values from the html to the controller

I'm trying to access the values a user introduces in a table from my controller.
This table is NOT part of the model, and the view source code is something like:
<table id="tableSeriales" summary="Seriales" class="servicesT" cellspacing="0" style="width: 100%">
<tr>
<td class="servHd">Seriales</td>
</tr>
<tr id="t0">
<td class="servBodL">
<input id="0" type="text" value="1234" onkeypress = "return handleKeyPress(event, this.id);"/>
<input id="1" type="text" value="578" onkeypress = "return handleKeyPress(event, this.id);"/>
.
.
.
</td>
</tr>
</table>
How can I get those values (1234, 578) from the controller?
Receiving a formcollection doesn't work since it does not get the table...
Thank you.
Using the FormCollection should work unless your table is not inside of a <form> tag
On top of Lazarus's comment, you can try this, but you have to set the name attribute for each:
<input id="seriales[0]" name="seriales[0]" type="text" value="1234" onkeypress="return handleKeyPress(event, this.id);"/>
<input id="seriales[1]" name="seriales[1]" type="text" value="578" onkeypress="return handleKeyPress(event, this.id);"/>
Now in your Action method you can make your method look like this:
[HttpPost]
public ActionResult MyMethod(IList<int> seriales)
{
// seriales.Count() == 2
// seriales[0] == 1234
// seriales[1] == 578
return View();
}
and seriales will be wired up to those values.
First Option:
Using FormCollection is the simplest way to access dynamic data. It is strange that you cannot get those values from it, can you check the following?
Is the table inside the
element?
Can you add name attribute
to the input elements? Note that
form items are bound by their names,
not id.
Second Option:
The second option is to add a collection in your model, and name everything accordingly. i.e.
public class MyModel
{
...
public IList<string> MyTableItems { get; set; }
}
and in your view use following names:
<input name="MyTableItems[]" value="" />

Spring mvc, how to bind a domain object that has a collection as its property

I have a domain object called Order, and it has a collection attribute called serviceOrders where a collection of service --- order m:m association relationships are hold.
public class Order implements Serializable {
private Long id = null;
private BigDecimal amountPaid;
private BigDecimal accountReceivable;
private User user;
private Set serviceOrders = new HashSet();
private Date closed;
private Date created = new Date();
private String status;
also there is a method for adding the association called addServiceOrder
public void addServiceOrder(ServiceOrder serviceOrder) {
if (serviceOrder == null)
throw new IllegalArgumentException("Can't add a null serviceOrder.");
this.getServiceOrders().add(serviceOrder);
}
how should I use commandName to set this collection with "path", I think it would only call its get set method of the Command Object. how should I add serviceOrder to this command Object. I have no idea about this problem. any help would be highly appreciated
Assuming your ServiceOrder instances have unique ids your service method should be #add(Long id).
Ok bear with me on this one but the solution is simple an annoying at the same time. I ran into this a couple of months ago. I am going to show you my solution using the jstl libraries in my view for handling the collections.
<c:forEach items="${Questions}" var="quest" varStatus="itemsIndex">
<fieldset>
<legend>${quest.section}</legend>
<form:form id="group${itemsIndex.index}" modelAttribute="ChoiceList" action="" method="POST" onsubmit="javascript:ajaxSave($(this).serialize()); return false;">
<a id="Group${quest.id}"></a>
<c:forEach items="${quest.qisQuestionsCollection}" var="quest2" varStatus="itemsRow">
<div style="font-weight: bold; margin: 10px 0px">${quest2.shortText}</div>
( ${quest2.qisQuestionTypes.description} )<br/>
( ${quest2.helpText} )<br/>
<a id="Question${quest2.id}"></a>
<c:choose>
<c:when test="${quest2.qisQuestionTypes.questionType == 'CHOOSEANY'}">
<c:forEach items="${quest2.qisChoicesCollection}" var="quest3" varStatus="indexStatus">
<c:forEach items="${ChoiceFields}" var="CField">
<c:set scope="request" value="${quest3}" var="ChoiceData"/>
<c:set scope="request" value="${CField}" var="ChoiceProperty"/>
<%
answerMap = (HashMap<QisChoice, Answer>) request.getAttribute("AnswerList");
choice = (QisChoice) request.getAttribute("ChoiceData");
if (answerMap.containsKey(choice.getChoiceID())) {
Answer theAnswer = (Answer) answerMap.get(choice.getChoiceID());
if (theAnswer != null) {
if (theAnswer.getChoiceValue() != null) {
request.setAttribute("itemValue", theAnswer.getChoiceValue());
request.setAttribute("itemSelected", true);
} else {
request.setAttribute("itemSelected", false);
request.setAttribute("itemValue", getReflectedValue(
(QisChoice) request.getAttribute("ChoiceData"),
(AccessorStruct) request.getAttribute("ChoiceProperty")));
}
}
} else {
request.setAttribute("itemSelected", false);
request.setAttribute("itemValue", getReflectedValue(
(QisChoice) request.getAttribute("ChoiceData"),
(AccessorStruct) request.getAttribute("ChoiceProperty")));
}
request.setAttribute("itemValue2", getReflectedValue(
(QisChoice) request.getAttribute("ChoiceData"),
(AccessorStruct) request.getAttribute("ChoiceProperty")));
%>
<c:choose>
<c:when test="${CField.visible == 'HIDDEN'}">
<form:hidden value="${itemValue2}" path="question[${itemsRow.index}].choice[${indexStatus.index}].${CField.beanName}" />
</c:when>
<c:otherwise>
<c:choose>
<c:when test="${itemSelected}">
<form:checkbox value="${itemValue}" label="${quest3.description}" path="question[${itemsRow.index}].choice[${indexStatus.index}].${CField.beanName}" checked="true" /><br/>
</c:when>
<c:otherwise>
<form:checkbox value="${itemValue}" label="${quest3.description}" path="question[${itemsRow.index}].choice[${indexStatus.index}].${CField.beanName}" /><br/>
</c:otherwise>
</c:choose>
</c:otherwise>
</c:choose>
</c:forEach>
</c:forEach>
</c:when>
<input type="submit" value="Save Section"
class="button-main" />
</fieldset>
</form:form>
</c:forEach>`
The Key bit is in this line
<form:checkbox value="${itemValue}" label="${quest3.description}" path="question[${itemsRow.index}].choice[${indexStatus.index}].${CField.beanName}" checked="true" /><br/>
To link up the command object with its collection for the postback you have to show the indice of the element as part of the spring path. In my case I have two levels of collections to track
<c:forEach items="${quest.qisQuestionsCollection}" var="quest2" varStatus="itemsRow">
varStatus gives you access to a bean object with the index property you can use to your advantage.
In your case you can do just use the index property of the foreach jstl function in the jsp to generate the indice like I did and append it to the array index notation of your command object. The command object must of course follow the same flow as the path collection names. This works for an infinite number of levels but gets more annoying as we go.
This is a large live example so if you need something smaller show me your markup and I will walk you throgh it.

Resources