PetaPoco complex types posting to controller - asp.net-mvc

As per a question that I asked yesterday I was trying to find a way to dynamically create more text boxes and have those map to my view's model so upon post to the server it will grab all the dynamically(js) generated text boxes and post that to an object such as a List.
To give an example of this confusing question:
I have a textbox that is labeled "Primary Contact" and the ticket creator can enter the contacts name and phone number into this box. What I want to do essentially is, switch this to three text boxes. One for Name, Email and PhoneNumber instead of one box. Then I will create some javascript that will dynamically create three more boxes to add another contact to this List collection. Then when the user submits the form to modify or create the ticket it passes this collection inside the model to the controller. However with petapoco it is a little confusing. Let me show you the controller:
[HttpPost]
public ActionResult ModifyTicket(Ticket model)
{
string userString = User.Identity.Name.Replace("ONHOLD\\", "");
if (ModelState.IsValid)
{
model.CreatedDate = DateTime.Now;
model.LastUpdateBy = Util.GetEmployeeIdByName(userString);
model.LastUpdate = DateTime.Now;
model.IsComplete = false;
model.ClientString = Util.GetClientNameById(model.ClientId);
model.LocationString = Util.GetLocationNameById(model.LocationId);
model.Update();
SuccessMessage = "You have successfully updated ticket number: " + model.TicketId + " for the following client: " + model.ClientString + ".";
return RedirectToAction("Index");
}
ErrorMessage = "Woops! Something went wrong, please check back in a few moments, if the problem persists please contact development.";
return RedirectToAction("Index");
}
The simple answer to this would be that my database model would contain a List object for this exact reason. However, I am using PetaPoco and I'm not entirely sure how it would be done. I could manually add in a collection to my Database model but when I regenerate my model based on any database schema changes I will lose any changes I've made to the file.
I am also using a partial class that my view uses for validation using DataAnnotations. However this class is identical to the database model it just contains DataAnnotations to provide client-side validation.
If anyone understands what I'm trying to accomplish I would be more than happyto provide more information to clarify any missing pieces. I just need a resolution to this as I can't find a solid way to go about resolving this issue!

Not entirely sure what you mean but it's easy to model bind from/to a list with MVC as you may already know. As for saving a deep object like this I'd use the [Ignore] attribute on the Ticket.List so it isn't persisted and handle it separately. I'd load the Contacts in separately from the Ticket object then manually add them to the Ticket object, alternatively use a join query and try the one-to-many approach to load it all in one go.
I think you're expecting Petapoco to update all in one? This won't happen you'll need to break it up. Hard to say from what you've written so far. There won't be a long list of contacts (from the sounds of it) so just insert or update them one by one.
Well that might help, or might not.

Related

MVC Display Offences List By User State

I am just starting learning MVC and I am stuck on this issue. I will appreciate if anyone has come across this before. Thanks
I would like to display the list by station. E.g Police of New-York can only see list of offences in New-York.
enter image description here This is the most recent change but still not working.
I would like to display the list of offences by the USER state.
At the moment I am displaying all the users regardless of their state id.
Here are two options that come to mind. One, you can filter out the offenses by iterating over them and pulling out only the values you need into a new list in C#. Two, you could edit the stored procedure to pass in parameters (such as a State ID or User ID) and then filter out the list of offenses returned from the database using a WHERE clause. Below is some sample code based on your image.
Idea One:
public ActionResult ViewOffenceList(int filterStateID)
{
PageModel model = new PageModel();
DBFile db = new DBFile();
var details = db.Offence.ToList();
List<Offence> filteredList = new List<Offence>();
foreach (var offence in details)
{
if (offence.StateID == filterStateID)
{
filteredList.Add(offence);
}
}
model.OffenceList = filteredList;
return View(model);
}
Idea Two:
CREATE PROCEDURE dbo.fwsp_GetOffenceList
#FilterStateID TINYINT
AS
SELECT *
FROM dbo.offences o
WHERE o.StateID = #FilterStateID
GO
These are just some quick overviews of the two options that come to mind given my experiences. In general, grab the ID of the state you wish to filter on, and use that to filter out which data to actually display. It sounds like you may have a User object which may have an associated State which you could use as the "filterStateID" in my examples.
If you're just starting out I'd suggest finding some tutorials online and walking through them. Here's one directly from Microsoft: https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/start-mvc?tabs=aspnetcore2x

connect two gsp screens to three domains in grails

so I am working on a web app when the users click on create on the list screen, it takes them to a page where they have to enter some information and then they click on "next" and it will take them to another gsp page where they have to enter data for two domains but none of the data are stored yet in the tables but when they click on "create" button, everything get stored in the database
I was looking for examples but couldnt find any.
I know how to call the record and edit it since all the domains or the tables share id number so I can use it to retrive data. but my problem is when I transfer from the first gsp screen to another I want to save the instance and then when the users click on create, data goes to the three tables
any idea how to do that? I am still beginner and trying to learn
thank you
It sounds kind confusing what you wanna do and I am not sure I completely understood. Because you want to change the whole page, and yet, not to lose those previous answers, right?. Is there a specific reason why you want to do this?
I believe you could sent all the information from the first gsp to a controller and save everything in the "session" (e.g session.name = params.name, session.age = params.age), redirect/render the other gsp and later on, you get the info back from the session plus the info that just came and save everything. This is probably not a very good solution, but this is the only way I figured this out.
:)
Just an idea, I haven't used it until now, but I will some day in the future to modify the dialog-flow in my current application...:
Wouldn't that be a good example for the webflow-plugin?
This is what command objects are used for. Any time you have a collection of data that you want to collect in a form and then "generate" multiple domain objects from, then this is the way.
The idea is to create a single class that has all the information that you want to collect on the form. You post the filled form data back to the controller save action which then validates that the data is complete using the command object constraints. Once you are happy with everything, you then use the data in the command object to create/update your domain objects.
We consider the use of command objects a Grails best practice. You can provide custom validation support in the command object that looks for and validates relationships in the data that are difficult to do with the domain objects. We often write factory methods in the command class that produce a new or updated domain object, making it very convenient for unit testing.
See the "Command Objects" section of the "Web Layer" in the manual for details. In Grails 2, command objects are classes with the #Validateable annotation and in Grails 3 they implement the Validateable trait. If you declare your command class as an inner class in the controller, then it is automatically validateable. We've found that we prefer to declare them in src/groovy rather than as inner classes because they are easier for someone unfamiliar with the code to find.
So amongst all of these answers you have your answer but in all honesty I think it is well beyond your own comprehension at this point.
Assuming you have this example as a form
http://code.runnable.com/UevQr3zfd_oaAAGn/jquery-ui-tabs
On tab 1 you have
Name
Age
On tab 2 you have
Address
Postcode
Then you have two domain class
Class User {
String name
String age
Address address
}
Class Address {
String address1
String postcode
}
So a user has name age and also binded to address, whilst address has address1 and postcode
now your controller action
def save(MyBean bean) {
Address address = new Address(bean.loadAddress()).save()
User user = new User()
def userMap = bean.loadUser()
user.age=userMap.age
user.name=userMap.name
//The above object that got saved first
user.addresss=address
user.save()
render "hopefully this should have saved it as expected"
}
In src/main/groovy/yourPackage/MyBean.groovy
package yourPackage
import grails.validation.Validateable
Class MyBean implements Validateable{
String name
String age
Address address
String address1
String postcode
//Now declare your constraints like your domainClass add validator where required to add additional verification/validation to your objects sent back
//This will return all the objects required as a map to save address domain class
protected Map loadAddress() {
Map results=[:]
results.with {
address1=address1
postcode=postcode
}
return results
}
//this will return the user object
protected Map loadUser() {
Map results=[:]
results.with {
name=name
age=age
}
}
}
Other fairly complex validation bean examples:
PhotosBean CustomerChatBean ScheduleBaseBean
Other points of reference:
As I say I think as a beginner this may take you a while to get your head around but hoping with what is provided it will become a lot clearer now
E2A
It is really complicated!! can I have two gsp screens instead of jquery tabs
That doesn't make much sense.
You can have two actions which one just passes params onto 2nd gsp ?
So
def TestController {
def index() {
render view: page1
}
//where page 1 is the first form and submits to action2
//action2 picks up parmas from page1
def action2() {
render view: page2, model:[params:params]
}
}
in page2.gsp you have
<g:form action="action3">
<g:hiddenField name="originalName" value="${params.originalValue}"/>
<g:hiddenField name="originalName2" value="${params.originalValue2}"/>
<g:hiddenField name="originalName3" value="${params.originalValue3}"/>
Then your actual form content
The problem with doing this this way, is does action2 need to verify params received from page1 ? if so it needs to either render original page or page2 depending.
Once submitted to page2 the hiddenFields can be tampered with by end user so what was validated may be invalid now. You will need some form of a way of revalidating all those again.
Using validation methods above you could just call the validate() functions or maybe build some md5 check of initial values vs what is now sent from page2.
Either way if you don't care about validation and just want to see it work then above is the simplest way.
can I have two gsp screens instead of jquery tabs
in page1 you can just do <g:include action="page2"> and include a 2nd gsp within first but in all honesty page 1 could have just contained both actions in 1 page. which is why it don't make sense

Dealing with complex models in ASP.NET MVC

I have a model that looks like this:
Business
- Branch
- Phone(*)
- Phone Type
- Number
- Opening hours (*)
- Days in week
- Working period (*)
- From time
- To time
- Custom field (*)
- Name
- Value
- Address
- Address line
- City
- State
- Zip
- Yada yada
I created Editor Templates for each of the class types above.
I want to have a common Business editor template with a submit form that posts the entire structure to a single action and saves it, both for an existing or new entity.
Is Editor Templates the right approach? How do I submit the form along its entire downline?
How do I make Add and Remove buttons to add/remove phone numbers within the form?
How do I order items in the collection (i.e. I want to have arrows near each phone number so the user can move it up or down in the client list, then handle the saving on server, for that I already have the solution).
Bottom line, my issue is how to get the right values posted back to the server, and how to modify the inner collections on the client. Once the proper data is on the server in this way or another I'll know how to deal with it. My problem is the client side and the correct way of data submission.
Update
I saw this answer, which basically answers the 1st part of my question, tho the latter two still remain (add-remove-order buttons - manage collections on client).
My problem is not how to add/remove/reorder rows at the client's DOM, but how to modify the client data and then receive it in the server in the action the looks like this:
[HttpPost]
public ActionResult Save(Business business)
{
/// blah blah
}
Update
Here is how I try to shove in the new data:
View:
#Ajax.ActionLink("Add", "AddCustomField", new AjaxOptions { UpdateTargetId = "customFields", InsertionMode = InsertionMode.InsertAfter })
Action:
public PartialViewResult AddOpeningTimes()
{
var ot = new OpeningTimes();
ot.WorkingPeriods.Add(new WorkingPeriod());
var e = EditorFor(ot);
//just here for debugging, the values are both empty strings
e.ViewData.TemplateInfo.HtmlFieldPrefix = ViewData.TemplateInfo.HtmlFieldPrefix;
return e;
}
//this method is on the base controller:
protected PartialViewResult EditorFor<TModel>(TModel model)
{
return PartialView("EditorTemplates/" + typeof(TModel).Name, model);
}
The thing is the name for the appropriate fields are not enumerated as needed (Branches[0].CustomField[0].Key), instead, it's just Key.
As far as i know, there is no 'simple' way to do this.
Add button - you have to wire javascript that creates a part of form (eg. phone type select and phone text box) and set its id/name. Basically you find the last item in the form, which will have name of Phone[x].PhoneType, and set the values on new part of form to appropriate values with x + 1.
An option to avoid generating the part the form by yourself is to create a hidden 'template' and copy that. Then change id and name.
Remove button - if you simply deleted items from DOM, you would create gaps in the sequence and MVC doesn't know how to deal with that. One possible approach is to mark items in the form as deleted using a hidden field, then handling that on the server.
Reordering - I would add a property called Order to whatever needs this feature, then render it as hidden and change using javascript when reordering. You also have to set it appropriately when adding an item.
Useful properties in these situations are also: IsNew, IsUpdated - along with IsDeleted allow for relatively easy processing on the server.
Of course, if you have nested collections each needing add/remove/reorder functionality it will be kind of difficult to do and debug.
UPDATE
The action rendering the partial view can't know what the html prefix should be, because it doesn't have the context (that the parent is Branch object etc.).
If you want to use AJAX, i would recommend sending the html field prefix as a parameter (public PartialViewResult AddOpeningTimes(string htmlPrefix)). htmlPrefix could be Branches[0].CustomField[last_custom_field + 1].. It's probably the cleanest way to achieve what you want, even if it's in fact not very clean.

How do I pass the userId into the model ASP.NET MVC?

I've had a thorough search around but really can't find anything addressing the scenario I'm facing (oddly because I'd have thought it's quite a common thing to do).
Background
I'm creating an application with ASP.NET MVC 4 and Entity Framework 5 Code First. For the purpose of this question, think of it as a blogging application with posts and users.
Project
The post model requires that every post have a corresponding UserId.
With the ASP.NET MVC 4 Membership it is easy to find the username of the person logged in with
User.Identity.Name.
This isn't ideal, we want the ID, but a query such as this can search the db for the name and get the ID.
db.UserProfiles.Single(a => a.UserName == User.Identity.Name);
Problem
The problem arises when trying to create a post. Model.IsValid is false, as no UserId is being passed in from the view. Obviously, as the user isn't expected to enter their ID.
I've tried putting the ID value into the ViewBag and using a #Html.Hidden() field in the view, however I've had no success with this. Model.IsValid always returns false.
Should this information be input through the create view? Or should it be done directly in the controller? Its quite a frustrating problem as I have the information and just need to figure how to pass it into the model.
CONTROLLER CODE
This is basically just the default scaffolded code. The commented code is how I tried setting the model value directly from the controller, however that was little more than trial and error.
//
// POST: /Post/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Post post)
{
if (ModelState.IsValid)
{
//var userId = db.UserProfiles.Single(a => a.UserName == User.Identity.Name);
//post.User.UserId = userId.UserId;
db.Posts.Add(post);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(post);
}
Be careful with hidden fields. Anyone could put whatever value they want in that field (i.e. they could spoof another user). You'd be better off caching the ID in the session at login, and using that value.
This is a typical case where you want to create an EditModel as a data transfer object (DTO) between your view and controller layers.
Create a class BlogPostEditModel that has all properties you need the user to fill in when creating a new blog post. Then, map this type (e.g. using AutoMapper) to your BlogPost entity, and fill in the user ID as well.
To use built-in validation such as Model.IsValid(), put the data annotations attributes on the DTO instead.
Honestly, I would have the value assigned via the controller. If you had someone messing with your html via Firebug, they could actually change the id before it was passed and submitted to your form. I would remove it from your Create view and submit from the controller.

Is this the correct usage of the ViewModel Pattern?

I'm using NerdDinner as a guide for my first MVC/LINQ to SQL project. It discusses the use of the ViewModel pattern when a View needs data from multiple sources - in their example: Dinners and Countries (serves as the drop down list).
In my application, the problem is a bit different. It's not so much different data, rather data linked via a key constraint. I have a Story table that links to aspnet_users via the UserId key. I would like to have easy access to the UserName for each story.
Since I'm using the repository pattern and returning IQueryable in some cases for deferred execution, I'm struggling with the correct way to shape the data. So I'm using this VideModel pattern right now to make it work but not sure if it's the right way.
Instead of returing IQueryable Story (which wouldn't work since I need the UserName), I'm returning a new custom class UserStory, which has a Story property and a string Username property.
What are your thoughts?
It seems like your question has less to do with MVC as it is simply a question about how to access the story data based on the username string.
Would it be possible to create a view in your database with all the UserStory data, the username, along with userid in it? That way, you could select from the view based on the username you have.
To create the view, you would simply have to do a join between the user table and the userstory table based on the userid.
After that, you could still use the repository pattern with the IQueryable being returned.
If you are wanting to do updates, it would be simple to do since you still have the userid, and would be able to link back to the actual table which would need the update.
If you look at Kigg, you will see that they mess about with the initial model to create custom ViewModels. That's the thing that NerdDinner doesn't cover in any detail. You could create a StoriesWithUserName class that inherits from Stories, but adds a new property - UserName. Then you return that to your View which would inherit from IEnumerable<StoriesWithUserName>
[EDIT]
Oops. Didn't spot that you already did this :o)
Using the repository pattern and returning an IQueryable of Stories is fine. The relationship allows you to access the the username value something like this >>
Assuming you are returning the IQueryable in your model object:
foreach(Story story in Model.Stories)
{
// do something with the value
response.write(story.aspnet_user.UserName);
};
Your Repository method would look like this:
public List<Stories> GetStories(Guid UserId)
{
return datacontext.Stories.Where(u => u.UserId = UserId).ToList();
}
The relationship will automatically provide you with access to the UserName value in the foreach loop i first mentioned. nothing more is required.
I'm not sure why your pagination control failed on Count() though??
Hope this helps

Resources