How to keep track of user's log-in/out in mvc - asp.net-mvc

This question may sound trivial, but to me is complicated. I have created a table that stores user's log-in/out date and time. So in my MVC site, I need to be able to insert a new row when the user logs-in and update the row when user clicks on x button or navigates away, etc.
I did a bit of research on "void Session_Start(object sender, EventArgs e)" and thought that might be my solution. However, when I run my site in debug mode in VS, even when I log-out and log-in as another user to the site, the method doesnt get called. Am i missing something, or Session_Start is used for a different purpose?
Any help would be hugely appreciated.

Example:
//Model
{
public class LoginHistory
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
public DateTime LoginTime { get; set; }
public DateTime? LogoutTime { get; set; }
[StringLength(128)]
public string UsertId { get; set; }
}
//Controller
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
//............
switch (result)
{
case SignInStatus.Success:
LoginTime(model.UserName);
return RedirectToLocal(returnUrl);
//...........
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
//...............................
LogOutTime(User.Identity.GetUserId());
//...............................
return RedirectToAction("Index", "Home");
}
public void LoginTime(string userName)
{
using (var db = new Applicationdbcontext())
{
var user = db.user.Find(u => u.UserName == userName);
var model = new LoginHistory
{
UserId = user.Id,
LoginTime = DateTime.UtcNow
LogoutTime = null,
};
db.loginhistory.Add(model);
db.SaveChanges();
}
public void LogOutTime(string userId)
{
using (var db = new Applicationdbcontext())
{
var model = db.loginhistory.Where(u => u.Uid == userId).OrderByDescending(u => u.Id).First();
model.LogoutTime = DateTime.UtcNow;
_login.SaveChanges();
}
}
<script type='text/javascript'>
var inFormOrLink;
$('a').on('click', function() { inFormOrLink = true; });
$('form').on('submit', function() { inFormOrLink = true; });
$(window).on("beforeunload", function() {
if(!inFormOrLink){
document.getElementById('logoutForm').submit();
}
})
add this script in your layout page.
I always follow this example. Hopefully it's help for you.

Related

Bundling with application cache in MVC4

I am working with an MVC project. And I use the application cache to store my whole page to the cache so that the application is still available even offline.
This is my Offline Controller
public class OfflineController : Controller
{
//
// GET: /Offline/
public ActionResult Index()
{
var manifestResult = new ManifestResult("1.0")
{
CacheResources = new List<string>()
{
Url.Action("Index", "Home"),
BundleTable.Bundles.ResolveBundleUrl("~/Content/css", true),
BundleTable.Bundles.ResolveBundleUrl("~/bundles/modernizr", true),
BundleTable.Bundles.ResolveBundleUrl("~/bundles/jquery",true),
BundleTable.Bundles.ResolveBundleUrl("~/bundles/jqueryui", true),
BundleTable.Bundles.ResolveBundleUrl("~/bundles/jqueryval",true),
BundleTable.Bundles.ResolveBundleUrl("~/bundles/modernizr",true),
BundleTable.Bundles.ResolveBundleUrl("~/Content/css",true),
BundleTable.Bundles.ResolveBundleUrl("~/Content/themes/base/css")
},
NetworkResources = new string[] { "*" },
FallbackResources = { { "Images/offline.jpg", "Images/offline.jpg" } }
};
return manifestResult;
}
}
My Home Controller is this
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
}
This is my class that generate the manifest file
public class ManifestResult : FileResult
{
public ManifestResult(string version)
: base("text/cache-manifest")
{
Version = version;
CacheResources = new List<string>();
NetworkResources = new List<string>();
FallbackResources = new Dictionary<string, string>();
}
public string Version { get; set; }
public IEnumerable<string> CacheResources { get; set; }
public IEnumerable<string> NetworkResources { get; set; }
public Dictionary<string, string> FallbackResources { get; set; }
protected override void WriteFile(HttpResponseBase response)
{
WriteManifestHeader(response);
WriteCacheResources(response);
WriteNetwork(response);
WriteFallback(response);
}
private void WriteManifestHeader(HttpResponseBase response)
{
response.Output.WriteLine("CACHE MANIFEST");
response.Output.WriteLine("#V" + Version ?? string.Empty);
}
private void WriteCacheResources(HttpResponseBase response)
{
response.Output.WriteLine("CACHE:");
foreach (var cacheResource in CacheResources)
response.Output.WriteLine(cacheResource);
}
private void WriteNetwork(HttpResponseBase response)
{
response.Output.WriteLine();
response.Output.WriteLine("NETWORK:");
foreach (var networkResource in NetworkResources)
response.Output.WriteLine(networkResource);
}
private void WriteFallback(HttpResponseBase response)
{
response.Output.WriteLine();
response.Output.WriteLine("FALLBACK:");
foreach (var fallbackResource in FallbackResources)
response.Output.WriteLine(fallbackResource.Key + " " + fallbackResource.Value);
}
}
Here is the error that I encounter
Before I answer, for those of you that just landed here, this is the implementation/article being referenced:
http://www.infoq.com/articles/Offline-Web-Apps
I was able to get this working just fine. One difference between your implementation and mine is that you are listing your manifest as such in the HTML tag:
<html manifest="/Offline">
.. or so I'm guessing.. you didn't post your HTML. I am not sure that HTML tag will be properly interpreted. Here is what I am using and works fine:
<html manifest="/Mobile/Manifest">
My guess is that "Application Cache Error event: Manifest fetch failed (-1)" is the equivalent of a 404.
Hope this helps... I see it's been quite a while since you posted.
I encountered the same issue of the css and script resources not loading in offline mode, when using the same infoq blog post as an example. I resolved the issue by adding the script and css resources using Scripts.Url instead of BundleTable.Bundles.ResolveBundleUrl.
My solution is based on a blog post by Eoin Clayton.
Using the Offline controller code you posted as a base, it may work if you modify it to look as follows:
public class OfflineController : Controller
{
//
// GET: /Offline/
public ActionResult Index()
{
var manifestResult = new ManifestResult("1.0")
{
CacheResources = new List<string>()
{
Url.Action("Index", "Home"),
Scripts.Url("~/bundles/jquery").ToString(),
Scripts.Url("~/bundles/modernizr").ToString(),
Scripts.Url("~/bundles/bootstrap").ToString(),
Scripts.Url("~/Content/css").ToString()
},
NetworkResources = new string[] { "*" },
FallbackResources = { { "Images/offline.jpg", "Images/offline.jpg" } }
};
return manifestResult;
}
}
Hope this helps.

Breeze Controller not returning proper response

I have a simple model, it is Entity Framework 5 Code First, ActiveEntity is an abstract class with an int Id property and a bool IsActive field.
public class License:ActiveEntity
{
public string LicenseName { get; set; }
public LicenseType LicenseType { get; set; }
public State State { get; set; }
public DateTime DateIssued { get; set; }
public int ValidFor { get; set; }
}
public class LicenseType:ActiveEntity
{
[StringLength(100),Required]
public string Description { get; set; }
}
public class State:ActiveEntity
{
[StringLength(2)]
[Required]
public string Name { get; set; }
[Display(Name = "Long Name")]
[Required, StringLength(25)]
public string LongName { get; set; }
}
Breeze makes a call to GetLicenses on the LicenseController:
[BreezeController]
public class LicenseController : ApiController
{
private readonly EFContextProvider<LicensingContext> db = new EFContextProvider<LicensingContext>();
[HttpGet]
public string Metadata()
{
return db.Metadata();
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return db.SaveChanges(saveBundle);
}
[HttpGet]
public IQueryable<License> GetLicenses()
{
//for debugging purposes
var retVal = db.Context.Licenses
.Include(l => l.State)
.Include(l=>l.LicenseType);
return retVal;
}
}
The db context returns the appropriate data but it does not appear in the response.
I don't have enough reputation points to post an image but the license type and state are in the context's response.
However the controller's response does not contain the licensetype object for the first three objects.
[{"$id":"1","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Low Voltage","State":{"$id":"2","$type":"Volt.Telecom.Licensing.Models.State, Volt.Telecom.Licensing.Models","Name":"FL","LongName":"Florida","IsActive":false,"Id":23},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":1},{"$id":"3","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Contractors","State":{"$ref":"2"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":2},{"$id":"4","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"General Contractors","State":{"$ref":"2"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":3},{"$id":"5","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Low Voltage","LicenseType":{"$id":"6","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"Low Voltage","IsActive":false,"Id":1},"State":{"$id":"7","$type":"Volt.Telecom.Licensing.Models.State, Volt.Telecom.Licensing.Models","Name":"CA","LongName":"California","IsActive":false,"Id":35},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":4},{"$id":"8","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Contractors","LicenseType":{"$id":"9","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"Contractors","IsActive":false,"Id":2},"State":{"$ref":"7"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":5},{"$id":"10","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"General Contractors","LicenseType":{"$id":"11","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"General Contractors","IsActive":false,"Id":3},"State":{"$ref":"7"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":6}]
Here is the home.js file on the client.
define(['services/logger'], function (logger) {
var system = require('durandal/system');
var serviceName = 'api/License';
// manager is the service gateway and cache holder
var manager = new breeze.EntityManager(serviceName);
var vm = {
activate: getLicenses,
title: 'Licenses',
licenses: ko.observableArray(),
includeExpired: ko.observable(false),
save: saveChanges,
show: ko.observable(false)
};
//vm.includeExpired.subscribe(getLicenses);
function getLicenses() {
log("querying Licenses", null, true);
var query = breeze.EntityQuery.from("GetLicenses");
//if (!vm.includeExpired()) {
// query = query.where("DateIssued.AddDays(ValidFor*-1)" > new Date(Date.now()));
//}
return manager
.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
// reload vm.todos with the results
function querySucceeded(data) {
log("queried Licenses", null, true);
vm.licenses(data.results);
vm.show(true); // show the view
}
}
function queryFailed(error) {
log("Query failed: " + error.message, null, true);
}
function saveChanges() {
return manager.saveChanges()
.then(function () { log("changes saved", null, true); })
.fail(saveFailed);
}
function saveFailed(error) {
log("Save failed: " + error.message, null, true);
}
function log(msg, data, showToast) {
logger.log(msg, data, system.getModuleId(vm), showToast);
}
return vm;
//#endregion
});
Any thoughts as to why this would occur and only for the first three items, any help would be appreciated. I like breeze as a potential for some spa's we need to write but this has caused me some concern.
Update 1
If I change the order of the LicenseType_id in the database it works, the initial order was 123123
if it is changed to 312123 or 321123 all six are correct in the response
[{"$id":"1","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Low Voltage","LicenseType":{"$id":"2","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"General Contractors","IsActive":false,"Id":3},"State":{"$id":"3","$type":"Volt.Telecom.Licensing.Models.State, Volt.Telecom.Licensing.Models","Name":"FL","LongName":"Florida","IsActive":false,"Id":23},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":1},{"$id":"4","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Contractors","LicenseType":{"$id":"5","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"Low Voltage","IsActive":false,"Id":1},"State":{"$ref":"3"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":2},{"$id":"6","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"General Contractors","LicenseType":{"$id":"7","$type":"Volt.Telecom.Licensing.Models.LicenseType, Volt.Telecom.Licensing.Models","Description":"Contractors","IsActive":false,"Id":2},"State":{"$ref":"3"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":3},{"$id":"8","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Low Voltage","LicenseType":{"$ref":"5"},"State":{"$id":"9","$type":"Volt.Telecom.Licensing.Models.State, Volt.Telecom.Licensing.Models","Name":"CA","LongName":"California","IsActive":false,"Id":35},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":4},{"$id":"10","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"Contractors","LicenseType":{"$ref":"7"},"State":{"$ref":"9"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":5},{"$id":"11","$type":"Volt.Telecom.Licensing.Models.License, Volt.Telecom.Licensing.Models","LicenseName":"General Contractors","LicenseType":{"$ref":"2"},"State":{"$ref":"9"},"DateIssued":"2012-11-18T00:00:00.000","ValidFor":1095,"IsActive":false,"Id":6}]
Edit: As of v 1.3.1 Breeze now DOES support inheritance.
The problem may be that Breeze does not yet support inheritance. There is a UserVoice suggestion here. Please vote on it. We take these suggestions very seriously.
To confirm that this is your issue, can you flatten the structure so that you do not need inheritance and see if the issue goes away.
I think that if something disappears between server to client its because Breeze retain null data column which can disorganize data structure and make knockout binding dysfunctional.
In opting to minimize Breeze performance you can place the attribute in the down level according to your need.
1 - BreezeWebApiConfig.cs level
2 - Controller level
3 - or HttGet level
This attribute works for me:
var jsonx = Breeze.WebApi.BreezeConfig.Instance;
jsonx.GetJsonSerializerSettings().NullValueHandling = Newtonsoft.Json.NullValueHandling.Include;

Entity framework savechanges error

I have a wizard step in which a user fills in fields. I then use json to save the values into my database for each wizard step.
However, in my repository I have my savechanges(). But it wont save the changes, instead it throws an error:
Entities in 'NKImodeledmxContainer.SelectedQuestion' participate in the 'QuestionSelectedQuestion' relationship. 0 related 'Question' were found. 1 'Question' is expected.
Anyone know how to get rid of the error? Do I have to get the ID from Question and save it aswell to my database or can I change something in EF so the error message is not getting thrown?
This is my post in my controller:
[HttpPost]
public JsonResult AnswerForm(int id, SelectedQuestionViewModel model)
{
bool result = false;
var goalCardQuestionAnswer = new GoalCardQuestionAnswer();
goalCardQuestionAnswer.SelectedQuestion = new SelectedQuestion();
goalCardQuestionAnswer.SelectedQuestion.Id = model.QuestionID;
goalCardQuestionAnswer.Comment = model.Comment;
goalCardQuestionAnswer.Grade = model.Grade;
if (goalCardQuestionAnswer.Grade != null)
{
answerNKIRepository.SaveQuestionAnswer(goalCardQuestionAnswer);
answerNKIRepository.Save();
result = true;
return Json(result);
}
answerNKIRepository.SaveQuestionAnswer(goalCardQuestionAnswer);
answerNKIRepository.Save();
return Json(result);
}
My Repository
public class AnswerNKIRepository
{
private readonly NKImodeledmxContainer db = new NKImodeledmxContainer();
public List<SelectedQuestion> GetAllSelectedQuestionsByGoalCardId(int goalCardId)
{
return db.SelectedQuestion.Where(question => question.GoalCard.Id == goalCardId).ToList();
}
public void SaveQuestionAnswer(GoalCardQuestionAnswer goalCardQuestionAnswer)
{
db.GoalCardQuestionAnswer.AddObject(goalCardQuestionAnswer);
}
public void Save()
{
db.SaveChanges();
}
}
This is my ViewModel:
public class SelectedQuestionViewModel
{
public int? Grade { get; set; }
public string Comment { get; set; }
public string SelectedQuestionText { get; set; }
public int QuestionID { get; set; }
}
This is my database model:
The exception complains that SelectedQuestion.Question is a required navigation property but you don't set this property in your code. Try to load the question by Id from the repository and set it to the SelectedQuestion.Question reference: Replace this line ...
goalCardQuestionAnswer.SelectedQuestion.Id = model.QuestionID;
...by...
goalCardQuestionAnswer.SelectedQuestion.Question =
answerNKIRepository.GetQuestionById(model.QuestionID);
And in your repository add the method:
public Question GetQuestionById(int id)
{
return db.Question.Single(q => q.Id == id);
}

Client side validation for my dropdown populated with enum values

I have a view where I use a dropdown list with enum:
public enum MaterialWorthEnumViewModel
{
[Display(Name = "")] Undefined,
[Display(Name = "< 1.000€")] LessThan1000,
[Display(Name = "1.000€ < 10.000€")] Between1000And10000,
[Display(Name = "10.000€ < 100.000€")] Between10000And100000,
[Display(Name = "100.000€ < 25.000.000€")] Between100000And25000000,
[Display(Name = "> 25.000.000€")] GreaterThan250000000,
}
I use a view model with this view:
public class MaterialEditNewViewModel
{
public int RequestID { get; set; }
...
[EnumRequired]
public MaterialWorthEnumViewModel MaterialWorth { get; set; }
}
As you can see above, I used a custom validation [EnumRequired] I grab the code from a blog online.
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)]
public class EnumRequiredAttribute : RequiredAttribute
{
private const string UNDEFINED_VALUE = "Undefined";
public string UndefinedValue { get; set; }
public EnumRequiredAttribute() : this(UNDEFINED_VALUE)
{ }
public EnumRequiredAttribute(string undefinedValue) : base()
{
if (String.IsNullOrWhiteSpace(undefinedValue))
{
throw new ArgumentNullException("undefinedValue");
}
UndefinedValue = undefinedValue;
}
public override bool IsValid(object value)
{
if (value == null)
{
return false;
}
var undefined = Enum.Parse(value.GetType(), UndefinedValue);
return !Enum.Equals(value, undefined);
}
}
Below is for the client side validation
public class ModelClientValidationEnumRequiredRule : ModelClientValidationRule
{
public ModelClientValidationEnumRequiredRule(string errorMessage, string undefinedValue)
{
base.ErrorMessage = errorMessage;
base.ValidationType = "enumrequired";
base.ValidationParameters.Add("undefinedvalue", undefinedValue);
}
}
public class EnumRequiredAttributeAdapter : DataAnnotationsModelValidator<EnumRequiredAttribute>
{
public EnumRequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, EnumRequiredAttribute attribute)
: base(metadata, context, attribute)
{ }
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
return new ModelClientValidationEnumRequiredRule[]
{
new ModelClientValidationEnumRequiredRule(base.ErrorMessage, Attribute.UndefinedValue)
};
}
}
Below is the javascript for the client side validation
Sys.Mvc.ValidatorRegistry.validators.enumrequired = function (rule) {
var undefinedValue = rule.ValidationParameters.undefinedvalue;
return function (value, context) {
return value != undefinedValue;
}
}
I also updated my GLobal.asax file:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(EnumRequiredAttribute), typeof(EnumRequiredAttributeAdapter));
The validation works pretty well on the server side but the client side validation is never triggered. So when I didn't choose any value on my view for my dropdown enum, I reach the action in the controller and then the server side validation occured and I go back to the view. I concluded that the client side validation didn't occurred.
Does someone can help me doing valid client side validation for this dropdown enum ?
Thanks. I'm a bit lost.
I don't see any relationship between your EnumRequiredAttribute and the other 2 classes. If you are using ASP.NET MVC 3 you need to associate your custom validation attribute with the adapter. This could be done in Application_Start:
DataAnnotationsModelValidatorProvider.RegisterAdapter(
typeof(EnumRequiredAttribute),
typeof(EnumRequiredAttributeAdapter)
);
Also on your client side you have shown some js code that relies on Microsoft*.js libraries. Those are now obsolete and should no longer be used. The default standard in ASP.NET MVC 3 for client side validation is the jquery.validate plugin.
So let's take an example.
Model:
public class MyViewModel
{
[EnumRequired]
public MaterialWorthEnumViewModel MaterialWorth { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
View (Index.cshtml):
#model MyViewModel
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/enumrequiredadapter.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.LabelFor(x => x.MaterialWorth)
#Html.EditorFor(x => x.MaterialWorth)
#Html.ValidationMessageFor(x => x.MaterialWorth)
<button type="submit">OK</button>
}
and finally the enumrequiredadapter.js adapter:
(function ($) {
$.validator.unobtrusive.adapters.add('enumrequired', ['undefinedvalue'], function (options) {
options.rules['enumrequired'] = options.params;
if (options.message != null) {
options.messages['enumrequired'] = options.message;
}
});
$.validator.addMethod('enumrequired', function (value, element, params) {
return value != params.undefinedvalue;
});
})(jQuery);
Also don't forget to remove all traces of Microsoft*.js script references from your site. And that's pretty much it.

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,

Resources