what should a method return from service layer - asp.net-mvc

I am just wondering about the way to validate my viewmodel.
A user can own only one team, so I have to check it somehow if he hasn't got one.
public ActionResult AddTeam(TeamCreatingViewModel teamToAdd)
{
if (ModelState.IsValid)
{
//check if the user has got a team
if (!TeamService.checkIfUserHasCreatedTeam(User.Identity.GetUserId()))
{
//if not then allow him to create one
if (!TeamService.addTeam(teamToAdd, User.Identity.GetUserId()))
{
ViewBag.Info = "Success";
return View("Info");
}
else
{
ViewBag.Info = "It was impossible to create a new team";
return View("Error");
}
}
else
{
ViewBag.info = "You have a team!";
return View("Error");
}
}
else
{
return View("TeamCreatingForm", teamToAdd);
}
}
Or would the solution below be better ?
public ActionResult AddTeam(TeamCreatingViewModel teamToAdd)
{
if (ModelState.IsValid)
{
if (!TeamService.addTeam(teamToAdd, User.Identity.GetUserId())) //<--- now it is checking and adding (if allowed)
{
ViewBag.Info = "Success";
return View("Info");
}
else
{
ViewBag.Info = "It was impossible to create a new team";
return View("Error");
}
}
else
{
return View("TeamCreatingForm", teamToAdd);
}
}
How can I report (from service layer) if an error has occured (and what kind of )? In the second case, users won’t know anything about what was done wrong.
And in the first case I have to get an entity object 2 times, what seems to be useless.

You can report errors from business layer by throw out param, for example
public bool AddItem(string name, out List<string> errors){...}// or just string with error

Related

db.savechanges() line freezes in EF

When the line db.savechanges() hits the breakpoint. Nothing happens. no errors in the catch block. The browser just freezes and data is not saved. I am using oracle with asp.net mvc. my code is given below;
public ResponseResult AddUserPermission(USER_PERMISSION permission)
{
try
{
_db.Entry(permission).State = EntityState.Modified;
_db.SaveChanges();
return new ResponseResult();
}
catch (Exception ex)
{
//return new ResponseResult();
return new ResponseResult(ResutlType.Error, ex.Message);
}
}
And the controller calls the method is given below:
[HttpPost]
[CustomAuthorize("Admin")]
public ActionResult Create(USER model)
{
try
{
string moduleId = Request.Form["ModuleId"];
string isSelected = Request.Form["IsSelected"];
model.DATE_CREATED = DateTime.Now;
model.DATE_UPDATED = DateTime.Now;
model.STATUS = (int)Status.Active;
var userPermission = processPermissionData(moduleId, isSelected);
//userPermission contains a list of permissions which i am trying to save
_userService.Add(model);
foreach (var permission in userPermission)
{
_userService.AddUserPermission(permission);
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I get no response from the browser or VS 15. All i get is the loading sign in the browser tab.

How to use Controller.TryUpdateModel outside of the Controller context?

is it possible to use Controller.TryUpdateModeloutside of the Controller context?
For Example suppose that I want to use Controller.TryUpdateModel method in class which does not belong to MyApp.Controllers so how that could be done?.
this is my code.
public ActionResult ValidateAndSignUp(company newCompany)
{
if (ModelState.IsValid)
{
newCompany.CDTO.File = Request.Files["Logo"];
if(new CompanyActions().AddCompany(newCompany))
{
ViewBag.message = newCompany.CDTO.Message;
return View(newCompany.CDTO.RedirectTo);
}
else
{
if (newCompany.CDTO.HasFileError)
{
ModelState.AddModelError("Logo", "Invalid File");
return View(newCompany.CDTO.RedirectTo, newCompany);
}
else
{
ViewBag.error = newCompany.CDTO.Error;
return View(newCompany.CDTO.RedirectTo);
}
}
}
else
{
newCompany.CDTO.Countries = new DropDownLists().GetAllCountries();
return View("signUp", newCompany);
}
}

i have been trying to implement custom login where i'll be updating the password but db.savechanges isn't working with my code

public ActionResult ChangePassword(ChangePassword model)
{
if (ModelState.IsValid)
{
UserDetail ud = db.UserDetails.FirstOrDefault(s => s.UserName == User.Identity.Name);
try
{
if (ud.Password == model.OldPassword)
{
ud.Password = model.NewPassword;
TryUpdateModel(ud);
**db.SaveChanges();**
return RedirectToAction("ChangePasswordSuccess");
}
else
{
ViewBag.ErrorMsgForPassword = "old password is not correct";
}
}
catch
{
return View();
}
}
while password change the complex types were not loaded so while updating he password db.savechanges() didn't work so if you load the complex types(addresses in this case) the problem is solved

RavenDB with asp.net mvc Update Issue

I have a small project in asp.net mvc 3 and I am using RavenDB to store data.
But when i am trying to update entity i have error saying
"Attempted to associate a different object with id 'orders/257'"
I have a service class to menage entities.
This is method to update entity called Order.
I'v omitted the rest of methods baceuse of clarity
public ErrorState UpdateOrder(Order order)
{
try
{
documentSession.Store(order);
documentSession.SaveChanges();
return new ErrorState { Success = true };
}
catch (Exception ex)
{
return new ErrorState { Success = false, ExceptionMessage = ex.Message };
}
}
This is rest of OrderRepository
private readonly IDocumentSession documentSession;
public OrderRepository(IDocumentSession _documentSession)
{
documentSession = _documentSession;
}
ErrorState class is for menagege errors in app, it contains bool success and string message of exception.
This is my edit Actions.
public ActionResult Edit(int id)
{
Order order = orderRepository.ObtainOrder(id);
if (order == null)
{
TempData["message"] = string.Format("Order no: {0} not found", id);
return RedirectToAction("Index");
}
return View(order);
}
[HttpPost]
public ActionResult Edit(Order order)
{
if(!ModelState.IsValid)
return View();
errorState = orderRepository.UpdateOrder(order);
if (errorState.Success)
{
TempData["message"] = string.Format("Order no: {0} has been changed", order.Id);
return RedirectToAction("Index");
}
else
{
TempData["Message"] = string.Format("Error on update order no: {0} MSG: {1}", order.Id,errorState.ExceptionMessage);
return RedirectToAction("Index");
}
}
This is the rest of the controller , I'v omitted the rest of actions baceuse of clarity.
private readonly IOrderRepository orderRepository;
private ErrorState errorState;
public HomeController(IOrderRepository _orderRepository,IDocumentSession _documentSession)
{
orderRepository = _orderRepository;
}
You already have an instance of an order with that id.
Check the session lifetime, is it possible that you have the same session across requests?

Entity Framework 4 w/ MVC 2 - fighting against EF4's inability to allow empty strings in form fields

FINAL EDIT: Success! There's a data annotation rule that stops empty strings from being set to null. I was able to use the solution here (Server-side validation of a REQUIRED String Property in MVC2 Entity Framework 4 does not work). Works like a charm now. I'll keep the rest of my post as-is in case anyone can learn from it.
Decided to rewrite this post to give all the detail I can. Long post, given all the code, so please bear with me.
I'm writing an MVC 2 project using EF4 as a base. All of my db columns are non-nullable.
Like I said before, I'm having issues with EF4 throwing a ConstraintException when I test the case of an empty form. The exception is springing up from the Designer.cs file, specifically in code like:
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.String GameTitle
{
get
{
return _GameTitle;
}
set
{
OnGameTitleChanging(value);
ReportPropertyChanging("GameTitle");
_GameTitle = StructuralObject.SetValidValue(value, false); // <-- this is where the exception is being thrown
ReportPropertyChanged("GameTitle");
OnGameTitleChanged();
}
}
private global::System.String _GameTitle;
partial void OnGameTitleChanging(global::System.String value);
partial void OnGameTitleChanged();
The exception IS NOT being caught and handled by MVC. Instead, I keep getting an uncaught exception and a YSoD. My controller (excuse the mess - I was trying to get repository level validation to work, see below):
[HttpPost]
public ActionResult CreateReview([Bind(Prefix = "GameData")]Game newGame, int[] PlatformIDs)
{
/* try
{
_gameRepository.ValidateGame(newGame, PlatformIDs);
}
catch (RulesException ex)
{
ex.CopyTo(ModelState);
}
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
else
{
var genres = _siteDB.Genres.OrderBy(g => g.Name).ToList();
var platforms = _siteDB.Platforms.OrderBy(p => p.PlatformID).ToList();
List<PlatformListing> platformListings = new List<PlatformListing>();
foreach(Platform platform in platforms)
{
platformListings.Add(new PlatformListing { Platform = platform, IsSelected = false });
}
var model = new AdminGameViewModel { GameData = newGame, AllGenres = genres, AllPlatforms = platformListings };
return View(model);
}*/
if (PlatformIDs == null || PlatformIDs.Length == 0)
{
ModelState.AddModelError("PlatformIDs", "You need to select at least one platform for the game");
}
try
{
foreach(var p in PlatformIDs)
{
Platform plat = _siteDB.Platforms.Single(pl => p == pl.PlatformID);
newGame.Platforms.Add(plat);
}
newGame.LastModified = DateTime.Now;
if (ModelState.IsValid)
{
_siteDB.Games.AddObject(newGame);
_siteDB.SaveChanges();
return RedirectToAction("Index");
}
else
{
return View();
}
}
catch
{
return View();
}
}
I've tried several things to get validation to work. The first was Steven Sanderson's "Let the model handle it" as described in his aPress MVC2 book. I figured the best place to attempt validation would be in the repository, since the data would have to be passed in there anyway, and I'd like to keep my controller thin. The repo:
public class HGGameRepository : IGameRepository
{
private HGEntities _siteDB = new HGEntities();
public List<Game> Games
{
get { return _siteDB.Games.ToList(); }
}
public void ValidateGame(Game game, int[] PlatformIDs)
{
var errors = new RulesException<Game>();
if (string.IsNullOrEmpty(game.GameTitle))
{
errors.ErrorFor(x => x.GameTitle, "A game must have a title");
}
if (string.IsNullOrEmpty(game.ReviewText))
{
errors.ErrorFor(x => x.ReviewText, "A review must be written");
}
if (game.ReviewScore <= 0 || game.ReviewScore > 5)
{
errors.ErrorFor(x => x.ReviewScore, "A game must have a review score, and the score must be between 1 and 5");
}
if (string.IsNullOrEmpty(game.Pros))
{
errors.ErrorFor(x => x.Pros, "Each game review must have a list of pros");
}
if (string.IsNullOrEmpty(game.Cons))
{
errors.ErrorFor(x => x.Cons, "Each game review must have a list of cons");
}
if (PlatformIDs == null || PlatformIDs.Length == 0)
{
errors.ErrorForModel("A game must belong to at least one platform");
}
if (game.Genre.Equals(null) || game.GenreID == 0)
{
errors.ErrorFor(x => x.Genre, "A game must be associated with a genre");
}
if (errors.Errors.Any())
{
throw errors;
}
else
{
game.Platforms.Clear(); // see if there's a more elegant way to remove changed platforms
foreach (int id in PlatformIDs)
{
Platform plat = _siteDB.Platforms.Single(pl => pl.PlatformID == id);
game.Platforms.Add(plat);
}
SaveGame(game);
}
}
public void SaveGame(Game game)
{
if (game.GameID == 0)
{
_siteDB.Games.AddObject(game);
}
game.LastModified = DateTime.Now;
_siteDB.SaveChanges();
}
public Game GetGame(int id)
{
return _siteDB.Games.Include("Genre").Include("Platforms").SingleOrDefault(g => g.GameID == id);
}
public IEnumerable<Game> GetGame(string title)
{
return _siteDB.Games.Include("Genre").Include("Platforms").Where(g => g.GameTitle.StartsWith(title)).AsEnumerable<Game>();
}
public List<Game> GetGamesByGenre(int id)
{
return _siteDB.Games.Where(g => g.GenreID == id).ToList();
}
public List<Game> GetGamesByGenre(string genre)
{
return _siteDB.Games.Where(g => g.Genre.Name == genre).ToList();
}
public List<Game> GetGamesByPlatform(int id)
{
return _siteDB.Games.Where(g => g.Platforms.Any(p => p.PlatformID == id)).ToList();
}
public List<Game> GetGamesByPlatform(string platform)
{
return _siteDB.Games.Where(g => g.Platforms.Any(p => p.Name == platform)).ToList();
}
}
}
The RulesException/Rule Violation classes (as taken from his book):
public class RuleViolation
{
public LambdaExpression Property { get; set; }
public string Message { get; set; }
}
public class RulesException : Exception
{
public readonly IList<RuleViolation> Errors = new List<RuleViolation>();
private readonly static Expression<Func<object, object>> thisObject = x => x;
public void ErrorForModel(string message)
{
Errors.Add(new RuleViolation { Property = thisObject, Message = message });
}
}
public class RulesException<TModel> : RulesException
{
public void ErrorFor<TProperty>(Expression<Func<TModel, TProperty>> property, string message)
{
Errors.Add(new RuleViolation { Property = property, Message = message });
}
}
That did not work, so I decided to try Chris Sells' method of using IDataErrorInfo (as seen here: http://sellsbrothers.com/Posts/Details/12700). My code:
public partial class Game : IDataErrorInfo
{
public string Error
{
get
{
if (Platforms.Count == 0)
{
return "A game must be associated with at least one platform";
}
return null;
}
}
public string this[string columnName]
{
get
{
switch (columnName)
{
case "GameTitle":
if (string.IsNullOrEmpty(GameTitle))
{
return "Game must have a title";
}
break;
case "ReviewText":
if (string.IsNullOrEmpty(ReviewText))
{
return "Game must have an associated review";
}
break;
case "Pros":
if (string.IsNullOrEmpty(Pros))
{
return "Game must have a list of pros";
}
break;
case "Cons":
if (string.IsNullOrEmpty(Cons))
{
return "Game must have a list of cons";
}
break;
}
return null;
}
}
}
}
Again, it did not work.
Trying simple data annotations:
[MetadataType(typeof(GameValidation))]
public partial class Game
{
class GameValidation
{
[Required(ErrorMessage="A game must have a title")]
public string GameTitle { get; set; }
[Required(ErrorMessage = "A game must have an associated review")]
public string ReviewText { get; set; }
[Required(ErrorMessage="A game must have a list of pros associated with it")]
public string Pros { get; set; }
[Required(ErrorMessage="A game must have a set of cons associated with it")]
public string Cons { get; set; }
}
}
Also did not work.
The common denominator with all of this is the EF designer throwing an exception, and the exception not being caught by MVC. I'm at a complete loss.
EDIT: Cross-posted from here: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/643e0267-fc7c-44c4-99da-ced643a736bf
Same issue with someone else: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/4fee653a-4c8c-4a40-b3cf-4944923a8c8d/
Personally i don't see a point in storing this in the database:
Id Description
1 Foo
2 ''
3 Bar
Seems silly to me.
Instead of storing blank fields you make it nullable.
If you disagree, then you could set a default value in the database, and set the StoreGeneratedPattern to Computed.
Or you could have a ctor for the entity, which sets the value.

Resources