RavenDB with asp.net mvc Update Issue - asp.net-mvc

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?

Related

Get recent inserted Id and send in to another controllers view

EDITED:
I have Created CRUD Functions for each Modals and now i am trying to get recent Inserted Id and use it in different view.
Here is what I have tried so far
I have created 2 classes(Layer based) for CRUD function for each ContextEntities db to practice pure OOP recursive approach and following is the code.
1. Access Layer
ViolatorDB
public class ViolatorDB
{
private TPCAEntities db;
public ViolatorDB()
{
db = new TPCAEntities();
}
public IEnumerable<tbl_Violator> GetALL()
{
return db.tbl_Violator.ToList();
}
public tbl_Violator GetByID(int id)
{
return db.tbl_Violator.Find(id);
}
public void Insert(tbl_Violator Violator)
{
db.tbl_Violator.Add(Violator);
Save();
}
public void Delete(int id)
{
tbl_Violator Violator = db.tbl_Violator.Find(id);
db.tbl_Violator.Remove(Violator);
Save();
}
public void Update(tbl_Violator Violator)
{
db.Entry(Violator).State = EntityState.Modified;
Save();
}
public void Save()
{
db.SaveChanges();
}
}
2. Logic Layer
ViolatorBs
public class ViolatorBs
{
private ViolatorDB objDb;
public ViolatorBs()
{
objDb = new ViolatorDB();
}
public IEnumerable<tbl_Violator> GetALL()
{
return objDb.GetALL();
}
public tbl_Violator GetByID(int id)
{
return objDb.GetByID(id);
}
public void Insert(tbl_Violator Violator)
{
objDb.Insert(Violator);
}
public void Delete(int id)
{
objDb.Delete(id);
}
public void Update(tbl_Violator Vioaltor)
{
objDb.Update(Vioaltor);
}
}
And Finally using Logic Layer functions in presentation Layer.Here insertion is performed as:
public class CreateViolatorController : Controller
{
public TPCAEntities db = new TPCAEntities();
private ViolatorBs objBs;
public CreateViolatorController()
{
objBs = new ViolatorBs();
}
public ActionResult Index()
{
var voilator = new tbl_Violator();
voilator=db.tbl_Violator.Add(voilator);
ViewBag.id = voilator.VID;
return View();
}
[HttpPost]
public ActionResult Create(tbl_Violator Violator)
{
try
{
if (ModelState.IsValid)
{
objBs.Insert(Violator);
TempData["Msg"] = "Violator Created successfully";
return RedirectToAction("Index");
}
else
{
return View("Index");
}
}
catch (Exception ex)
{
TempData["Msg"] = "Failed..." + ex.Message + " " + ex.ToString();
return RedirectToAction("Index");
}
}
}
Now here is the main part how do i get perticuller inserted id in another controller named Dues while performing insertion ?
In sqlqery I would have used ##IDENTITY but in Entity Framework I'm not sure.
I'm new to mvc framework any suggestion or help is appreciated Thanks in Advance.
Once you save your db context the id is populated back to your entity by EF automatically.
for example.
using(var context = new DbContext())
{
var employee = new Employee(); //this has an id property
context.Employees.Add(employee);
context.SaveChanges();
var id = employee.id; // you will find the id here populated by EF
}
You dont need to add and save your table as you have done this already in your voilatorDB class just fetch the last id like following
var id = yourTableName.Id;
db.yourTableName.find(id);
Or you can simply write one line code to achive that using VoilatorBs class function
GetbyID(id);

dependency injection - convert ninject di to lightinject di

How do I convert the following Ninject DI to the equivalent for LightInject DI? I'm having issues with getting to the right syntax.
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());
kernel.Bind<UserAccountService>().ToSelf();
kernel.Bind<AuthenticationService>().To<SamAuthenticationService>();
kernel.Bind<IUserAccountQuery>().To<DefaultUserAccountRepository>().InRequestScope();
kernel.Bind<IUserAccountRepository>().To<DefaultUserAccountRepository>().InRequestScope();
On my original question, I didn't include this, but this (also posted as comment to this post) was the not working code I attempted to make it work:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DefaultMembershipRebootDatabase, BrockAllen.MembershipReboot.Ef.Migrations.Configuration>());
container.Register<UserAccountService>();
container.Register<AuthenticationService, SamAuthenticationService>();
container.Register<IUserAccountQuery, DefaultUserAccountRepository>(new PerRequestLifeTime());
container.Register<IUserAccountRepository, DefaultUserAccountRepository>(new PerRequestLifeTime());
The error message (without the stack trace) given was this:
Exception Details: System.InvalidOperationException: Unresolved dependency [Target Type: BrockAllen.MembershipReboot.Ef.DefaultUserAccountRepository], [Parameter: ctx(BrockAllen.MembershipReboot.Ef.DefaultMembershipRebootDatabase)], [Requested dependency: ServiceType:BrockAllen.MembershipReboot.Ef.DefaultMembershipRebootDatabase, ServiceName:]
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
*If anyone wants to see the stack trace too - * just ask, and I'll post it in a reply to this question.
The constructor for DefaultMembershipRebootDatabase (as was in a sample project, my project used the dll provided through nuget, and the constructor wasn't available, but I'm pretty sure they're more than likely the same in both cases (seeing as how it comes from the same source...) is:
public class DefaultMembershipRebootDatabase : MembershipRebootDbContext<RelationalUserAccount>
{
public DefaultMembershipRebootDatabase()
: base()
{
}
public DefaultMembershipRebootDatabase(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
public DefaultMembershipRebootDatabase(string nameOrConnectionString, string schemaName)
: base(nameOrConnectionString, schemaName)
{
}
}
This is the constructor (as was in the same aforementioned sample project) for the DefaultUserAccountRepository:
public class DefaultUserAccountRepository
: DbContextUserAccountRepository<DefaultMembershipRebootDatabase, RelationalUserAccount>,
IUserAccountRepository
{
public DefaultUserAccountRepository(DefaultMembershipRebootDatabase ctx)
: base(ctx)
{
}
IUserAccountRepository<RelationalUserAccount> This { get { return (IUserAccountRepository<RelationalUserAccount>)this; } }
public new UserAccount Create()
{
return This.Create();
}
public void Add(UserAccount item)
{
This.Add((RelationalUserAccount)item);
}
public void Remove(UserAccount item)
{
This.Remove((RelationalUserAccount)item);
}
public void Update(UserAccount item)
{
This.Update((RelationalUserAccount)item);
}
public new UserAccount GetByID(System.Guid id)
{
return This.GetByID(id);
}
public new UserAccount GetByUsername(string username)
{
return This.GetByUsername(username);
}
UserAccount IUserAccountRepository<UserAccount>.GetByUsername(string tenant, string username)
{
return This.GetByUsername(tenant, username);
}
public new UserAccount GetByEmail(string tenant, string email)
{
return This.GetByEmail(tenant, email);
}
public new UserAccount GetByMobilePhone(string tenant, string phone)
{
return This.GetByMobilePhone(tenant, phone);
}
public new UserAccount GetByVerificationKey(string key)
{
return This.GetByVerificationKey(key);
}
public new UserAccount GetByLinkedAccount(string tenant, string provider, string id)
{
return This.GetByLinkedAccount(tenant, provider, id);
}
public new UserAccount GetByCertificate(string tenant, string thumbprint)
{
return This.GetByCertificate(tenant, thumbprint);
}
}
And this is the controller in my project:
namespace brockallen_MembershipReboot.Controllers
{
using System.ComponentModel.DataAnnotations;
using BrockAllen.MembershipReboot;
using BrockAllen.MembershipReboot.Mvc.Areas.UserAccount.Models;
public class UserAccountController : Controller
{
UserAccountService _userAccountService;
AuthenticationService _authService;
public UserAccountController(AuthenticationService authService)
{
_userAccountService = authService.UserAccountService;
_authService = authService;
}
// GET: /UserAccount/
[Authorize]
public ActionResult Index()
{
return View();
}
public ActionResult Login()
{
return View(new LoginInputModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginInputModel model)
{
if (ModelState.IsValid)
{
/*BrockAllen.MembershipReboot.*/UserAccount account;
if (_userAccountService.AuthenticateWithUsernameOrEmail(model.Username, model.Password, out account))
{
_authService.SignIn(account, model.RememberMe);
_authService.SignIn(account, model.RememberMe);
/*if (account.RequiresTwoFactorAuthCodeToSignIn())
{
return RedirectToAction("TwoFactorAuthCodeLogin");
}
if (account.RequiresTwoFactorCertificateToSignIn())
{
return RedirectToAction("CertificateLogin");
}
if (_userAccountService.IsPasswordExpired(account))
{
return RedirectToAction("Index", "ChangePassword");
}*/
if (Url.IsLocalUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
return RedirectToAction("Index");
}
else
{
ModelState.AddModelError("", "Invalid Username or Password");
}
}
return View(model);
}
public ActionResult Register()
{
return View(new RegisterInputModel());
}
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult Register(RegisterInputModel model)
{
if (ModelState.IsValid)
{
try
{
var account = _userAccountService.CreateAccount(model.Username, model.Password, model.Email);
ViewData["RequireAccountVerification"] = _userAccountService.Configuration.RequireAccountVerification;
return View("Success", model);
}
catch (ValidationException ex)
{
ModelState.AddModelError("", ex.Message);
}
}
return View(model);
}
}
}
The constructor for AuthenicationService is:
public abstract class AuthenticationService : AuthenticationService<UserAccount>
{
public new UserAccountService UserAccountService
{
get { return (UserAccountService)base.UserAccountService; }
set { base.UserAccountService = value; }
}
public AuthenticationService(UserAccountService userService)
: this(userService, null)
{
}
public AuthenticationService(UserAccountService userService, ClaimsAuthenticationManager claimsAuthenticationManager)
: base(userService, claimsAuthenticationManager)
{
}
}
By default, LightInject does not resolve concrete classes without registering them, while NInject does.
For example, NInject can resolve DefaultMembershipRebootDatabase without registering it, while LightInject cannot by default. Take a look at this.
In any way, to fix your issue, make sure that you register your concrete classes (that are needed as dependencies in other classes). Here is an example:
container.Register<DefaultMembershipRebootDatabase>();
I am assuming here that some class has a dependency on the concrete class DefaultMembershipRebootDatabase. If you have other concrete class dependencies, make sure that you also register them.
You should use the PerScopeLifetime rather than the PerRequestLifetime. PerRequestLifetime represents a transient lifetime that tracks disposable instances and disposes them when the scope ends. PerScopeLifetime ensures the same instance within a scope which in this case means the same instance within a web request.

ASP.NET MVC Web API : Posting a list of objects

I'm trying to post a list of objects from my winforms application to my asp.net mvc 4 website. I've tested posting one object, and it works, but does not work for the list. It returns a 500 (Internal Server Error). Here is my code:
ASP.NET MVC Web API
public class PostTraceController : ApiController
{
public HttpResponseMessage Post(List<WebTrace> list)
{
try
{
// Some code
return Request.CreateResponse(HttpStatusCode.Created);
}
catch (Exception ex)
{
HttpContext.Current.Trace.Write("exception", ex.Message);
return Request.CreateErrorResponse(HttpStatusCode.ServiceUnavailable, ex);
}
}
public HttpResponseMessage Post(WebTrace item)
{
try
{
// Some code
return Request.CreateResponse(HttpStatusCode.Created);
}
catch (Exception ex)
{
HttpContext.Current.Trace.Write("exception", ex.Message);
return Request.CreateErrorResponse(HttpStatusCode.ServiceUnavailable, ex);
}
}
}
Win forms application
public class BaseSender
{
public BaseSender()
{
Client = new HttpClient
{
BaseAddress = new Uri(#"http://localhost/mywebsite/")
};
Client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public string UserCode { get; set; }
protected readonly HttpClient Client;
public HttpResponseMessage PostAsJsonAsync(string requestUri, object value)
{
var response = Client.PostAsJsonAsync(requestUri, value).Result;
response.EnsureSuccessStatusCode();
return response;
}
}
public class WebTraceSender : BaseSender
{
private const string requestUri = "api/posttrace";
public bool Post(List<ArchiveCptTrace> list)
{
try
{
var listWebTrace = new List<WebTrace>();
foreach (var item in list)
{
listWebTrace.Add(new WebTrace
{
DateStart = item.DatePreparation,
DateEnd = item.DateCloture,
UserStart = item.UserPreparation.UserName,
UserEnd = item.UserCloture.UserName,
AmountStart = item.MontantPreparation,
AmountEnd = item.MontantCloture,
TheoricAmountEnd = item.MontantTheorique,
Difference = item.Ecart,
UserCode = UserCode
});
}
var responce = PostAsJsonAsync(requestUri, listWebTrace);
return responce.IsSuccessStatusCode;
}
catch (Exception e)
{
// TODO : Trace the exception
return false;
}
}
}
EDIT :
I've found out the scenario of the error, which is having two methods in my api controller, even thought they have different signature. If I comment one method, the post work fine (item or a list). Any ideas ?
The methods may have different signatures, but Web API can't tell the difference between them without inspecting the body, which it won't do for performance reasons.
You could do two things - either create a new class which just holds a list of WebTrace objects, and put that in a different API controller, or you could map a custom route to one of your existing methods. You could do that with ActionName attribute, however, I would probably take the first approach.

Using ViewModels in asp.net mvc 3

Here is my scenario: (These all have to accomplished in the same view as an accepted requirement)
User enters a few search criterias to search users.
Page lists the search results with an update link besides.
User clicks on one of the update links and a form appears to enable editing the data.
User does changes and saves the data that binded to form.
I used a view model for this view. Here it is.
[Serializable]
public class UserAddModel
{
public UserSearchCriteria UserSearchCriteria { get; set; }
public UserEntity User { get; set; }
public List<UserPrincipalDto> SearchResults { get; set; }
}
And here is my controller:
using System;
namespace x.Web.BackOffice.Controllers
{
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
[Authorize(Roles = "Admin")]
public class UserController : Controller
{
private readonly IAuthentication _authentication;
private readonly List<RoleEntity> roles = new Y.Framework.Data.Repository<RoleEntity>().Get(null).ToList();
private Repository<UserEntity> repository = new Repository<UserEntity>();
[ImportingConstructor]
public UserController(IAuthentication authentication)
{
this._authentication = authentication;
}
public ActionResult Index()
{
return View(new UserAddModel());
}
[HttpPost]
public ActionResult GetSearchResults(UserAddModel model)
{
if (ModelState.IsValid)
{
try
{
List<UserPrincipalDto> results =
_authentication.SearchUsers(
ConfigurationManager.AppSettings["DomainName"],
model.UserSearchCriteria.FirstName,
model.UserSearchCriteria.LastName,
model.UserSearchCriteria.Username);
model.SearchResults = results;
Session["UserAddModel"] = model;
return View("Index", model);
}
catch (Exception ex)
{
Logger.Log(ex, User.Identity.Name);
}
}
else
{
ModelState.AddModelError("", "Error!");
}
Session["UserAddModel"] = model;
return View("Index", model);
}
public ActionResult Save(string username)
{
UserAddModel model = Session["UserAddModel"] as UserAddModel;
UserEntity exists = repository.Get(u => u.Username == username).FirstOrDefault();
if (exists == null)
{
UserPrincipal userPrincipal =
_authentication.GetUserDetails(
ConfigurationManager.AppSettings["DomainName"],
username);
model.User = new UserEntity();
model.User.Id = userPrincipal.Guid.Value;
model.User.FirstName = userPrincipal.DisplayName.FullNameToFirstName();
model.User.LastName = userPrincipal.DisplayName.FullNameToLastName();
model.User.Email = userPrincipal.EmailAddress;
model.User.Username = userPrincipal.SamAccountName;
}
else
{
model.User = new UserEntity();
model.User.Id = exists.Id;
model.User.FirstName = exists.FirstName;
model.User.LastName = exists.LastName;
model.User.Email = exists.Email;
model.User.Username = exists.Username;
model.User.RoleId = exists.RoleId;
}
ViewBag.Roles = roles;
return View("Index", model);
}
[HttpPost]
public ActionResult Save(UserAddModel model)
{
UserEntity exists = repository.Get(u => u.Id == model.User.Id).FirstOrDefault();
if (exists == null)
{
Result result = repository.Save(model.User);
HandleResult(result, model);
}
else
{
Result result = repository.Save(model.User, PageMode.Edit);
HandleResult(result, model);
}
ViewBag.Roles = roles;
return View("Index", model);
}
}
}
As you see there are two different forms in my view and I'm storing the whole view model in Session in my controller. But I think this is not fine enough. What if session expires or what if I have to deploy my application using a load balancer?
What is the best way to develop this kind of page? I'm open to any kind of suggestions.
Thanks in advance,

Mvc 3 validation of property that throws an exception

I have a property on my Model Class that performs a type conversion as follows:
Model:
public class TimeClass
{
private int timeInSeconds;
[Required]
public int Id {get;set;}
[Required]
public string Timer
{
get {
TimeSpan ts = new TimeSpan(0,0,(int)timeInSeconds);
return ts.ToString(#"mm\:ss",CultureInfo.InvariantCulture);
}
set {
try {
var ts = TimeSpan.ParseExact(value, #"mm\:ss", CultureInfo.InvariantCulture);
timeInSeconds= Convert.ToInt32(ts.TotalSeconds);
}
catch {
//Is it possible to add a validation error to the modelstate here
}
}
}
}
Controller:
[HttpPost]
public ActionResult Create(FormCollection collection)
{
string[] whitelist = new[] {"Id", "Timer" };
if (TryUpdateModel(quiz, whitelist))
{
//Save to Repo
return RedirectToAction("Edit", new { Id = Id });
}
return View(tc);
}
What is the appropriate pattern to add an appropriate ModelError if the TimeSpan.Parse throws an exception?
Currently it will give the generic error "The value "xxx" is invalid". How can I customize this to return a specific error?
Rather than putting the try catch within your model, you could move the error handling to your controller code. For example if the tryupdatemodel throws an exception you could add a custom model error:
TimeClass model = new TimeClass();
string[] whitelist = new[] {"Id", "Timer" };
try
{
UpdateModel(model);
//Save to Repo
return RedirectToAction("Edit", new { Id = Id });
}
catch
{
// Generate error
ModelState.AddModelError(string.Empty, "Model Error Here");
return View(tc);
}

Resources