ASP.NET MVC : Attends / Likes Post - c#

I have an Event with info about it on a Display Event View. On that view, I am trying to to make Attend functuality, similar to Liking, but I have little problems. My logic is very simple and I would like to keep it so: on click, it will increase int Attends by 1, but ...
First-I am getting inside the if(events==null)... And second is there a way to make it clickable once per User?
Here is my code:
Model:
[Key]
public int Id { get; set; }
public string EventName { get; set; }
...
public int Attends { get; set; }
Event Create Action:
//POST: Event/Create
[HttpPost]
public ActionResult Create(EventViewModel model)
{
if (ModelState.IsValid)
{
using (var database = new EventSpotDbContext())
{
var events = new Event(model.EventName,...);
...
events.Attends = 0;
database.Events.Add(events);
database.SaveChanges();
return RedirectToAction("Main");
}
}
return View(model);
}
Event Attend Action:
public ActionResult Attend(int? id)
{
using (var database = new EventSpotDbContext())
{
var events = database.Events.FirstOrDefault(a => a.Id == id);
if (events == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
events.Attends += 1;
database.SaveChanges();
}
return RedirectToAction("Details");
}
Event Details Action:
//GET: Event/Details
public ActionResult Details(int? id)
{
using (var database = new EventSpotDbContext())
{
var events = ... .First();
return View(events);
}
}
Details View
#model EventSpot.Models.Event
...
#Html.ActionLink("Attend Event", "Attend", "EventController", new {#id=Model.Id} )
#Model.Attends

#Html.ActionLink("Attend Event", "Attend", "EventController", new {#id=Model.Id}, null )
the isse that he was dealing with {#id=Model.Id} as html attributes not route attributes

Related

How do i confirm the action delete(POST) in my controller?

I have a ViewModel and I would like to make a fonctionnal delete(GET) and deleteConfirmed(POST) so i can delete what ever data is stored in my DB
I don’t know and would like to know what step to take to complete the deleteConfirmed. There is normally auto-generated code but it’s not what I need.
here is my ViewModel
using System;
using ExploFormsDB.Models;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ExploFormsDB.ViewModels
{
public class WorkShiftDetailViewModel
{
[Key]
public int WorkShiftId { get; set; }
public int? HoleId { get; set; }
public string HoleName { get; set; }
public int SurveyLocationId { get; set; }
public int SupplierId { get; set; }
public int ZoneId { get; set; }
public string SurveyLocation1 { get; set; }
public string SupplierName { get; set; }
public string ZoneName { get; set; }
public DateTime StartDay { get; set; }
public DateTime EndDay { get; set; }
public ICollection<WorkerViewModel> WorkShiftEmployees { get; set; }
}
}
Here is my Controller, i have included the Create to help have a better understanding. GET: Delete seems to be working correctly, i am having trouble with the Post. any help what so ever will do. if the question as been answered already please send me a link. I'm pretty new to c# and core and completly new to ViewModels
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(WorkShiftDetailViewModel workShiftDetailViewModel)
{
if (!ModelState.IsValid)
{
WorkShift ws = new WorkShift();
ws.StartDay = workShiftDetailViewModel.StartDay;
ws.EndDay = workShiftDetailViewModel.EndDay;
ws.SupplierId = workShiftDetailViewModel.SupplierId;
ws.SurveyLocationId = 1;
ws.ZoneId = workShiftDetailViewModel.ZoneId;
ws.HoleId = workShiftDetailViewModel.HoleId;
_context.Add(ws);
await _context.SaveChangesAsync();
foreach (WorkerViewModel member in workShiftDetailViewModel.WorkShiftEmployees)
{
if (member.isDeleted == false) {
WorkShiftTeam emp = new WorkShiftTeam();
emp.EmployeeId = member.EmployeeId;
emp.RoleId = member.RoleId;
emp.WorkShiftId = ws.WorkShiftId;
_context.Add(emp);
}
}
HttpContext.Session.SetInt32("wsId", ws.WorkShiftId);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(CreateSharedView));
}
return View(workShiftDetailViewModel);
}
public IActionResult Delete(int? id)
{
if (id == null)
{
return NotFound();
}
List<WorkerViewModel> Workers = new List<WorkerViewModel>();
WorkShift ws = _context.WorkShift.Include(w => w.WorkShiftTeam).SingleOrDefault(x => x.WorkShiftId == id);
WorkShiftDetailViewModel detail = new WorkShiftDetailViewModel();
detail.HoleName = ws.HoleId == null ? "N/A" : _context.Hole.Find(ws.HoleId).HoleName;
detail.StartDay = ws.StartDay;
detail.EndDay = ws.EndDay;
detail.ZoneName = _context.Zone.Find(ws.ZoneId).ZoneName;
detail.SurveyLocation1 = _context.SurveyLocation.Find(ws.SurveyLocationId).SurveyLocation1;
detail.SupplierName = _context.Supplier.Find(ws.SupplierId).SupplierName;
detail.WorkShiftId = ws.WorkShiftId;
int order = 0;
var rolelist = new SelectList(_context.Role, "RoleId", "Role1");
var empsWithFullName = from e in _context.Employee.Where(a => a.IsActive)
select new
{
ID = e.EmployeeId,
FullName = e.LastName + ", " + e.FirstName
};
var empList = new SelectList(empsWithFullName, "ID", "FullName");
foreach (WorkShiftTeam member in ws.WorkShiftTeam.OrderBy(a => a.EmployeeId))
{
Workers.Add(new WorkerViewModel() { EmployeeId = member.EmployeeId, RoleId = member.RoleId, Index = order, Roles = rolelist, Employees = empList });
order++;
}
detail.WorkShiftEmployees = Workers;
return View(detail);
}
// POST: WorkShiftDetailViewModels/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
//??
} ```
Why you created an extra method for delete action as HttpGet? (that occurred conflict)
change it to:
[HttpGet]
public IActionResult GetById(int? id) { ... }
and just one delete method with this definition
[HttpPost]
public async Task<IActionResult> Delete(int? id) { ... }

Editing Many to Many in Entity Framework. Can add but not remove

In my POST Edit function, I have my viewmodel that contain the game I want to update and list of platformIds that I want to add to the game.
Using this code, I was able to add platforms to my game but can't remove them. I put a breakpoint at the end and definitely see that viewModel.Game.Platforms have only what I selected but it is not updated in my game list.
If I add a few platforms and remove some at the same time. The new platforms get added but none are removed.
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> platforms = new List<Platform>();
foreach (var id in viewModel.PostedPlatforms.PlatformIds)
{
platforms.Add(db.Platforms.Find(Int32.Parse(id)));
}
db.Games.Attach(viewModel.Game);
viewModel.Game.Platforms = platforms;
db.Entry(viewModel.Game).State = EntityState.Modified;
UpdateModel(viewModel.Game);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Game);
}
The model class is
public class Game
{
public int GameId { get; set; }
public string Title { get; set; }
public List<Platform> Platforms { get; set; }
}
public class Platform
{
public int PlatformId { get; set; }
public string Name { get; set; }
public List<Game> Games { get; set; }
}
Using ourmandave's suggestion, I got this code which while does change the platforms selection, it creates a new game entry every time which is inefficient and also increasing the id of the content which mess up bookmarks.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> platforms = new List<Platform>();
if(viewModel.PostedPlatforms != null)
{
foreach (var id in viewModel.PostedPlatforms.PlatformIds)
{
platforms.Add(db.Platforms.Find(Int32.Parse(id)));
}
}
db.Games.Remove(db.Games.Find(viewModel.Game.PostId));
db.SaveChanges();
viewModel.Game.Platforms = platforms;
db.Games.Add(viewModel.Game);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Game);
}
You could try this...
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> selectedPlatforms = viewModel.Select(pl => GetPlatformById(pl.Id)).ToList();
var game = GetGameById(viewModel.Id);
UpdateGamePlatforms(game, selectedPlatforms);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Game);
}
private Platform GetPlatformById(int platformId)
{
return db.Platforms.First(pl => pl.Id == platformId);
}
private Game GetGameById(int gameId)
{
return db.Games.First(g => g.Id == gameId);
}
private void UpdateGamePlatforms(Game game, IList<Platform> selectedPlatforms)
{
var gamePlatforms = game.Platforms.ToList();
foreach (var gamePlatform in gamePlatforms)
{
if (selectedPlatforms.Contains(gamePlatform) == false)
{
game.Platforms.Remove(gamePlatform);
}
else
{
selectedPlatforms.Remove(gamePlatform);
}
}
game.Platforms.AddRange(selectedPlatforms);
}
UpdateGamePlatformswill remove platforms from the game which are no longer selected. It will leave the platforms which are still selected and it will also add new platforms to the game which have been selected.
Solution: Using TomJerrum's solution, I can now edit the platform list properly. To update the rest of the properties, I have to map all the property of the game object I'm trying to edit to match the property of my viewModel. Thankfully, there is already a function for that so I only have to add db.Entry(game).CurrentValues.SetValues(viewModel.game);.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(GameViewModel viewModel)
{
if (ModelState.IsValid)
{
List<Platform> selectedPlatforms = new List<Platform>();
if (viewModel.PostedPlatforms != null)
{
int[] platformIds = Array.ConvertAll(viewModel.PostedPlatforms.PlatformIds, p => Convert.ToInt32(p));
selectedPlatforms.AddRange(db.Platforms.Where(item => platformIds.Contains(item.PlatformId)).ToList());
}
var game = GetGameById(viewModel.Id);
UpdateGamePlatforms(game, selectedPlatforms);
db.Entry(game).CurrentValues.SetValues(viewModel.game);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(viewModel.Review);
}
private Game GetGameById(int gameId)
{
return db.Games.First(g => g.Id == gameId);
}
private void UpdateGamePlatforms(Game game, IList<Platform> selectedPlatforms)
{
var gamePlatforms = game.Platforms.ToList();
foreach (var gamePlatform in gamePlatforms)
{
if (selectedPlatforms.Contains(gamePlatform) == false)
{
game.Platforms.Remove(gamePlatform);
}
else
{
selectedPlatforms.Remove(gamePlatform);
}
}
game.Platforms.AddRange(selectedPlatforms);
}

Calculated attributes in model results in The requested attribute does not exist

Having trouble update users in AD
My Model:
public class UserModel
{
....
[ScaffoldColumn(false)]
[DisplayName("Fødselsdag")]
[DataType(DataType.Date)]
[NotMapped]
public DateTime extensionAttribute1_date
{
get
{
try
{
return DateTime.Parse(extensionAttribute1);
}
catch (Exception e)
{
return new DateTime();
}
}
set { }
}
}
My Controller:
[HttpPost]
public ActionResult Edit(string sAMAccountName, FormCollection collection, UserModel data)
{
if (ModelState.IsValid)
{
var config = new LdapConfiguration();
config.ConfigureFactory("domain.local").AuthenticateAs(new NetworkCredential("xxxx", "xxxxx"));
using (var context = new DirectoryContext(config))
{
var user = context.Query(new UserModel(), "OU=users,OU=xxx,DC=xxx,DC=dk", "User").FirstOrDefault(d => d.sAMAccountName == sAMAccountName);
if (user == null) return RedirectToAction("Index");
user.title = data.title;
user.mobile = data.mobile;
user.homePhone = data.homePhone;
user.streetAddress = data.streetAddress;
user.postalCode = data.postalCode;
user.l = data.l;
user.department = data.department;
user.physicalDeliveryOfficeName = data.physicalDeliveryOfficeName;
user.extensionAttribute1 = data.extensionAttribute1_date.ToLongDateString();
context.Update(user);
}
return RedirectToAction("Index");
}
return View();
}
When i submit to Edit Action i results in an error:
The requested attribute does not exist.
If i remove extensionAttribute1_date from the model i updates fine.
How do i exclude my calculated attributes from the update?
I have other attributes in the model such as Age which is calculated! Is this the wrong procedure for this?
/Michael

Two dropdowns in one view, second dependent on what is selected on first

Just started messing around with MVC and have been trying to accomplish this by looking at this example:
http://forums.asp.net/t/1670552.aspx
I keep getting this error:
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Line 9: #using (Html.BeginForm("Index","Home",FormMethod.Post, new{id = "ID"})){
Line 10: #Html.DropDownListFor(m=>m.id, new SelectList(Model.list, "id","name"),"selectThis")
Line 11: }
Here is the code:
Model classes (stupid names, I know):
These are in a console application used only to store models.
namespace Model
{
public class Model
{
public int id { get; set; }
public string name { get; set; }
}
public class List
{
public int id { get; set; }
public List<Model> list = new List<Model>();
}
public class subModel
{
public int id { get; set; }
public int modId { get; set; }
public string name { get; set; }
}
public class subList
{
public List<subModel> list = new List<subModel>();
}
}
Controller: (was populating subList.list and List.list with methods in the class, but decided to try it this way now, was getting the same error)
namespace DropboxTest.Controllers
{
public class HomeController : Controller
{
//
// GET: /Model/
public ActionResult Index()
{
LoadModel();
return View();
}
[ValidateInput(false)]
[AcceptVerbs("POST")]
public ActionResult Index([Bind(Exclude = "id")]Model.Model model)
{
var modId = Request["id"];
LoadModel();
LoadSubCategory(Convert.ToInt32(modId));
return View();
}
public void LoadModel()
{
Model.List listM = new Model.List();
listM.id = 0;
Model.Model mod1 = new Model.Model();
mod1.id = 1;
mod1.name = "me";
Model.Model mod2 = new Model.Model();
mod2.id = 2;
mod2.name = "me";
listM.list.Add(mod1);
listM.list.Add(mod2);
ViewBag.Model = listM;
}
public void LoadSubCategory(int id)
{
Model.subList subList = new Model.subList();
Model.subModel sub1 = new Model.subModel();
Model.subModel sub2 = new Model.subModel();
sub1.id = 1;
sub1.name = "notme";
sub1.modId = 1;
sub2.id = 1;
sub2.name = "notme";
sub2.modId = 1;
subList.list.Add(sub1);
subList.list.Add(sub2);
List<Model.subModel> sel = new List<Model.subModel>();
foreach (var item in subList.list)
{
if (item.modId == id)
{
sel.Add(item);
}
}
ViewBag.SubModel = sel;
}
}
}
View: (I have no idea if anything for subModel dropdown is working as I haven't even gotten to that part yet, but w/e.)
#model Model.List
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
#using (Html.BeginForm("Index","Home",FormMethod.Post, new{id = "ID"})){
#Html.DropDownListFor(m=>m.id, new SelectList(Model.list, "id","name"),"selectThis")
}
#if (ViewBag.SubModel != null)
{
#Html.DropDownList("SubModel",ViewBag.SubModel as SelectList, "select one")
}
It's probably something really stupid but I've been stuck for a couple of hours trying different things.
PS: This is just a test app. After I see how it is done I will be doing one with and SQL DB, using models in ConsoleApplications to retrieve and store data from the DB and display it in views, so any advice on that will be also appreciated.
A big thank you to all that have read up to here and have a nice day.
You never pass a model to the view in the controller, you just store in ViewBag.Model.
Try something as follows:
[ValidateInput(false)]
[AcceptVerbs("POST")]
public ActionResult Index([Bind(Exclude = "id")]Model.Model model)
{
var modId = Request["id"];
//get model
var model = LoadModel();
//pass it to the view
return View(model);
}

Updating model after HttpPost

I want to update existing Product objects in database by images, but image goes to DB successfully only when i create new objects.
I'm trying to update my object this way
[HttpPost]
public ActionResult Edit(Product product, HttpPostedFileBase image)
{
if (ModelState.IsValid)
{
if (image != null)
{
product.ImageMimeType = image.ContentType;
product.ImageData = new byte[image.ContentLength];
image.InputStream.Read(product.ImageData, 0, image.ContentLength);
}
if (product.ProductID != 0)
UpdateModel<Product>(repository.Products.FirstOrDefault(p => p.ProductID == product.ProductID));
repository.SaveProduct(product);
TempData["message"] = string.Format("{0} has been saved", product.Name);
return RedirectToAction("Index");
}
return View(product);
}
//repository.SaveProduct()
public void SaveProduct(Product product)
{
if (product.ProductID == 0)
{
context.Products.Add(product);
}
context.SaveChanges();
}
The View
#
Upload new image: input type="file" name="Image"
input type="submit" value="Save"
#Html.ActionLink("Cancel and return to List", "Index")
}
I noticed you were read the "Pro ASP.NET MVC 3 Framework" and meet this issue same to me.
The author had a error at here, the code should be(You must reference and using the System.Data.Entity namespace at first):
public void SaveProduct(Product product)
{
if (product.ProductID == 0)
{
context.Products.Add(product);
}
else
{
context.Entry(product).State = System.Data.EntityState.Modified;
}
context.SaveChanges();
}
This is all kinds of wrong.
You should be using specific ViewModels for your Edit and Create actions.
Define a separate class containing the properties you wish to edit and any UI validation:
public class EditProductViewModel {
[HiddenInput]
public int Id {get;set;}
[Required]
public string Name {get;set;}
[Required]
public string Description {get;set;}
public HttpPostedFileBase Image {get;set;}
}
Then change your action method like so:
[HttpPost]
public ActionResult Edit(EditProductViewModel viewModel) {
if (ModelState.IsValid) {
var product = repository.Products.FirstOrDefault(p => p.Id == viewModel.Id);
// TODO - null check of product
// now lefty righty
product.Name = viewModel.Name;
product.Description = viewModel.Description;
if (viewModel.Image.ContentLength > 0) {
product.ImageMimeType = image.ContentType; // wouldn't trust this (better to lookup based on file extension)
product.ImageData = new byte[image.ContentLength];
image.InputStream.Read(product.ImageData, 0, image.ContentLength);
}
repository.SaveProduct(product);
return RedirectToAction("Index");
}
return View(viewModel);
}
Here's a good post discussing the ViewModel pattern.
Try doing this
context.Products.Attach(product);
Note: only when doing the update, not when inserting a new product.
Try this:
public void SaveProduct(Product product)
{
if (product.ProductID == 0)
{
context.Products.Add(product);
}
else // Update operation
{
context.Products.Attach(product);
}
context.SaveChanges();
}
Note: I would change the way you determine which is it a new or an updated product.
[HttpPost]
public RedirectToRouteResult Save(TestViewModel viewModel)
{
TempData["Output"] = "Here is some response";
return RedirectToAction("Index", viewModel);
}

Categories