WebApi controller fails - thread culture issue - c#

I have a controller method that fails on the return statement
[HttpGet("{id}")]
public UserModel Get(int id)
{
System.Threading.Thread.CurrentThread.CurrentCulture =
new System.Globalization.CultureInfo("en-CA");
System.Threading.Thread.CurrentThread.CurrentUICulture =
new System.Globalization.CultureInfo("en-CA");
BP.DataAccess.DataUtilities.DatabaseCommand.ConnectionString =
_configuration["connectionStrings:PrimaryConnection"];
UserModel user = UserService.GetUserById(id);
return user;
}
The UserModel class has:
public int RoleTypeId { get; set; }
private ListModels.RoleTypeModel _RoleType;
public ListModels.RoleTypeModel RoleType
{
get
{
_RoleType = Trisura.BP.Core.ListServices
.RoleTypeService.GetRoleTypeById(RoleTypeId);
return _RoleType;
}
private set { _RoleType = value; }
}
public static RoleTypeModel GetRoleTypeById(int id)
{
int cultureId = CultureService.GetThreadCultureId();
List<ListModels.RoleTypeModel> localizedList =
GetRoleTypesLocalizedList(cultureId);
ListModels.RoleTypeModel roleTypeModel =
localizedList.Where(roletype => roletype.Id == id).FirstOrDefault();
if (roleTypeModel == null)
{
throw new CoreExceptions.ObjectNotFoundInDatabaseException(
string.Format("The requested role type (ID = {0}) was not found.", id));
}
return roleTypeModel;
}
public static RoleTypeModel GetRoleTypeById(int id)
{
// this returns "en-US" (0) instead of "en-CA" (1)
int cultureId = CultureService.GetThreadCultureId();
List<ListModels.RoleTypeModel> localizedList = GetRoleTypesLocalizedList(cultureId);
ListModels.RoleTypeModel roleTypeModel =
localizedList.Where(roletype => roletype.Id == id).FirstOrDefault();
if (roleTypeModel == null)
{
throw new CoreExceptions.ObjectNotFoundInDatabaseException(
string.Format("The requested role type (ID = {0}) was not found.", id));
return roleTypeModel;
}
}
when the controller hits return user;, it fails because the thread CurrentCulture is set to en-US even I explicitly said that culture is en-CA.
Does anyone have an explanation? Does this happen in a separate thread?
How to ensure that my model will run with the same culture?

Related

How to initialize DateTime property to show Date.Now

I am trying to set DateTime Field to display current time and date.
public DateTime Date { get; set; }
What I try so far to pass in setter Date.Now but doesn't work.
I am asking because I need to display DateTime.Now in View but this items should be hidden from User.
User can only see DateTime but can not Edit.
Also in Controller I use something like but doesn't work
DateTime Date = DateTime.Now;
Any idea where I made mistake and how to fix this issues ?
UPDATE
Here is my Controller
public NotesController(ApplicationDbContext db)
{
_db = db;
}
public IActionResult Index()
{
IEnumerable<Notes> notes = _db.Notes.Include(u => u.Patient);
return View(notes);
}
//Upsert GET
public IActionResult Upsert(int? Id)
{
DateTime Date = DateTime.Now;
NotesVM notesVM = new NotesVM()
{
Notes = new Notes(),
PatientSelectList = _db.Patients.Select(i => new SelectListItem
{
Text = i.FirstName + i.LastName,
Value = i.Id.ToString()
})
};
Notes notes = new Notes();
if (Id == null)
{
// this is for create
return View(notesVM);
}
else
{
// this is for edit
notesVM.Notes = _db.Notes.Find(Id);
if (notesVM.Notes == null)
{
return NotFound();
}
return View(notesVM);
}
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Upsert(NotesVM notesVM)
{
if (ModelState.IsValid)
{
if (notesVM.Notes.Id == 0)
{
//Creating
_db.Notes.Add(notesVM.Notes);
}
else
{
//Updating
_db.Notes.Update(notesVM.Notes);
}
_db.SaveChanges();
return RedirectToAction("Index");
}
notesVM.PatientSelectList = _db.Patients.Select(i => new SelectListItem
{
Text = i.FirstName + i.LastName,
Value = i.Id.ToString()
});
return View(notesVM);
}
If you have a constructor for your controller you can set the date property like this:
public NotesController(ApplicationDbContext db)
{
_db = db;
Date = DateTime.Now;
}
updated my answer now that i have seen your constructor.

Mapping string rules to LINQ expressions, including expressions containing own methods for authorisation

In an MVC app, I want to implement a set of rules, which super users can create, read, update and delete.
Each rule explicitly allows/forbids a user to perform an action in the format:
<Allow || Deny> userId <action_key> <condition>
The action key would be something like "DoSomeAction" as a string.
I then intend to use those rules for authorisation inside controllers for
authorisation. For example:
//GET ViewProduct/id
public ActionResult ViewProduct(string productId)
{
var product = // get product from repository;
if(RulesAuthorizer.Authorise("ViewProduct", User.Identity.GetUserId(), product){
//proceed to product... JSON or partial view, etc.
}
return new HttpStatusCodeResult(403);
}
ViewProduct is an example action_key above.
In the Authorise(string action_key, string userId, object ruleArg = null) method, I would load all the user relevant rules from the DB for this action key and decide if the user should be allowed.
However, and this is really the question, how could I use a condition for a rule as a string. For example, a condition would be:
a user must be a member of the group "Customers" and the product must not be of type "cheese" or
a custom method result such as if the product was added by group X, and group Y must not see it, I could have my method Product.GetAddedBy() and include this method in the LINQ expression.
How could I store such conditions as strings for each rule and then build LINQ expressions from them?
I intend to pass the object in question (Product in the example) in the optional ruleArg parameter.
Any ideas are much appreciated for a convenient way to store strings, which can be made into LINQ expressions at run time or any alternative approach such as perhaps map conditions to delegates with parameters?
Here is an example of user access via Attributes using strings to determine what they have access to. This is using Action/Controller to determine access but you can modify it for any string(s) you want.
Decorate the controller(s) with [AuthoriseByRole]
First the Attribute
namespace PubManager.Authorisation
{
public class AuthoriseByRoleAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
var isAuthorized = base.AuthorizeCore(httpContext);
if (!isAuthorized && httpContext.Request.IsAjaxRequest())
{
httpContext.Response.StatusCode = 401;
httpContext.Response.End();
}
if (isAuthorized)
{
var request = httpContext.Request;
var r = request.RequestContext.RouteData.Values["r"]
?? request["r"];
var currentUser = (UserModel) HttpContext.Current.Session["user"];
if (currentUser == null)
{
currentUser = HttpContext.Current.User.GetWebUser();
}
var rd = httpContext.Request.RequestContext.RouteData;
string currentAction = rd.GetRequiredString("action");
string currentController = rd.GetRequiredString("controller");
if (currentUser.HasAccess(currentController, currentAction))
return true;
}
httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return false;
}
}
}
Then the UserModel that is used to determine access:
namespace PubManager.Domain.Users
{
public class UserModel
{
public int UserId { get; set; }
public string UserName { get; set; }
public string Title { get; set; }
[Required]
[DisplayName("Forename")]
public string FirstName { get; set; }
[Required]
public string Surname { get; set; }
[Required]
[DisplayName("Company name")]
public DateTime? LastLogin { get; set; }
public bool LockedOut { get; set; }
public DateTime? LockedOutUntil { get; set; }
public bool IsGlobalAdmin { get; set; }
public bool? IsSystemUser { get; set; }
public IEnumerable<RoleModel> Roles { get; set; }
public bool HasAccess(string controller, string view)
{
if (IsGlobalAdmin || IsSystemUser.Value)
{
return true;
}
var isAuthorized = false;
if (!Roles.Any())
return false;
foreach (var role in Roles)
{
if (role.PageToRoles == null)
return false;
foreach (var pg in role.PageToRoles)
{
if (pg.RolePage.Controller.Equals(controller, StringComparison.InvariantCultureIgnoreCase) && (pg.RolePage.View.Equals(view, StringComparison.InvariantCultureIgnoreCase) || pg.RolePage.View.Equals("*")))
isAuthorized = true;
}
}
return isAuthorized;
}
}
}
Finally the GetWebUser class to get the user
namespace PubManager.Domain.Users
{
public static class SecurityExtensions
{
public static string Name(this IPrincipal user)
{
return user.Identity.Name;
}
public static UserModel GetWebUser(this IPrincipal principal)
{
if (principal == null)
return new UserModel();
var db = new DataContext();
var user = (from usr in db.Users
where usr.UserName == principal.Identity.Name
select new UserModel
{
Title = usr.Person.Title,
UserName = usr.UserName,
FirstName = usr.Person.FirstName,
Surname = usr.Person.LastName,
Email = usr.Person.Email,
LockedOut = usr.LockedOut,
UserId = usr.UserId,
IsSystemUser = usr.IsSystemUser,
IsGlobalAdmin = usr.IsGlobalAdmin.Value,
PersonId = usr.PersonId,
Roles = from r in usr.UserToRoles
select new RoleModel
{
RoleId = r.RoleId,
PageToRoles = from ptr in r.Role.PageToRoles
select new PageToRoleModel
{
RolePage = new RolePageModel
{
Controller = ptr.RolePage.Controller,
View = ptr.RolePage.View
}
}
}
}).FirstOrDefault();
if (user != null)
{
HttpContext.Current.Session["user"] = user;
}
return user;
}
}
}

Perform CRUD in controller with ViewModel in ASP.NET MVC

From my two models Student and InventoryRecord. I created a ViewModel named TestViewModel. I'm confused as to how do I write my controller?
public class TestViewModel
{
//from Student model
[Key]
public string UserID { get; set; }
public string PhoneNumber{ get; set; }
public string Address{ get; set; }
//other properties
//from Inventory model
public string FathersName { get; set; }
public string FathersAddress { get; set; }
//other properties
}
When I'm using only my main model Student. This is how I write my controller:
// GET: Students/CreateEdit
public ActionResult InventoryRecord()
{
var currentUserId = User.Identity.GetUserId();
var newid = db.Students.FirstOrDefault(d => d.UserID == currentUserId);
if (newid == null)
{
newid = db.Students.Create();
newid.UserID = currentUserId;
db.Students.Add(newid);
}
Student student = db.Students.Find(newid.UserID);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
// POST: Students/CreateEdit
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult InventoryRecord(Student student)
{
var currentUserId = User.Identity.GetUserId();
var userName = User.Identity.GetUserName();
var u = db.Students.FirstOrDefault(d => d.UserID == currentUserId);
if (u == null)
{
u = db.Students.Create();
u.UserID = currentUserId;
db.Students.Add(u);
}
if (ModelState.IsValid)
{
u.PhoneNumber = student.PhoneNumber;
u.Address = student.Address;
//other properties
db.SaveChanges();
TempData["Message"] = "User: " + userName + ", details successfully updated!";
}
return View(student);
}
Now, I'm really confused how to proceed here. How should I write my controller if I'm using my TestViewModel? Someone please point me in the right direction. Thank you.
Well personally I would move the code out of the controller.
However for example you just need to create an instance of your TestViewModel and pass that to your view. You may also need to update your View if you specific the model in the cshtml.
public ActionResult InventoryRecord()
{
var currentUserId = User.Identity.GetUserId();
var newid = db.Students.FirstOrDefault(d => d.UserID == currentUserId);
if (newid == null)
{
newid = db.Students.Create();
newid.UserID = currentUserId;
db.Students.Add(newid);
}
Student student = db.Students.Find(newid.UserID);
if (student == null)
{
return HttpNotFound();
}
TestViewModel model = new TestViewModel
{
UserID = student.UserId,
PhoneNumber = student.PhoneNumber,
//add the rest.
};
return View(model);
}
Rather than returning Student , return TestViewModel
Student student = db.Students.Find(newid.UserID);
if (student == null)
{
return HttpNotFound();
}
TestViewModel tvm = new TestViewModel()
{
UserID =student.Id,
PhoneNumber = student.PhoneNumber,
Address= student.Address
};
return View(tvm);
}
and second method will be
public ActionResult InventoryRecord(TestViewModel tvm)

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

how to return guid from a class in the controller

Is there a way I can return a Guid with the code below? For example, what I'm passing in to AddSchedule is a class. I want to return an Id from the class so I can so something with it in the controller. How would I change my code to resolve this?
Controller
ModelService.AddSchedule(
new Schedule
{
Id = Guid.Empty,
Start = start,
Stop = end
});
What I want to do with the return Guid
ModelService.AddScheduleToPerson(
new Schedule
{
Id = ?, // get this from above
UserId = userid,
User = username
});
Model
public ObjectCreateStatus AddSchedule(Schedule schedule)
{
var client = new Services.ConfigurationClient();
try
{
ConfigurationMessage cMsg =
client.ConfigService.AddSchedule(
this.ControllerBase.SessionVariables.Credentials,
schedule
);
if (cMsg.Result == ConfigurationResultEnum.Success)
return ObjectCreateStatus.Success;
return ObjectCreateStatus.GeneralError;
}
finally
{
client.Close();
}
}
If you are looking to return a GUID as well as an ObjectCreateStatus you could consider using an out parameter for it.
public ObjectCreateStatus AddSchedule(Schedule schedule, out Guid guid) { }
I'd create a wrapper object that can contain both your ObjectCreateStatus and your Guid and return that. Something like this:
public class ObjectCreateResult
{
public ObjectCreateStatus CreateStatus { get; set; }
public Guid CreateGuid { get; set; }
}
public ObjectCreateResult AddSchedule(Schedule schedule)
{
ObjectCreateResult result = new ObjectCreateResult();
var client = new Services.ConfigurationClient();
try
{
ConfigurationMessage cMsg =
client.ConfigService.AddSchedule(
this.ControllerBase.SessionVariables.Credentials,
schedule
);
if (cMsg.Result == ConfigurationResultEnum.Success)
{
result.CreateStatus = ObjectCreateStatus.Success;
result.CreateGuid = Guid.NewGuid(); // Set your actual Guid here
}
else
{
result.CreateStatus = ObjectCreateStatus.GeneralError;
result.CreateGuid = Guid.Empty;
}
}
finally
{
client.Close();
}
return result;
}
You can use an out parameter. I'm assigning the GUID at the beginning of the method, but you may want to change that logic depending on your requirements. Here's your modified code:
public ObjectCreateStatus AddSchedule(Schedule schedule, out Guid theGuid)
{
theGuid = Guid.NewGuid();
var client = new Services.ConfigurationClient();
try
{
ConfigurationMessage cMsg =
client.ConfigService.AddSchedule(
this.ControllerBase.SessionVariables.Credentials,
schedule
);
if (cMsg.Result == ConfigurationResultEnum.Success)
return ObjectCreateStatus.Success;
return ObjectCreateStatus.GeneralError;
}
finally
{
client.Close();
}
}
Consider making the ObjectCreateStatus a class:
public class ObjectCreateStatus {
public bool WasSuccessful { get; private set; }
public Guid ScheduleId { get; private set; }
ctor(ConfigurationResultEnum result, Guid guid) {
WasSuccessful = result == ConfigurationResultEnum.Success;
ScheduleId = guid
}
}
public ObjectCreateStatus AddSchedule(Schedule schedule)
{
var client = new Services.ConfigurationClient();
try
{
ConfigurationMessage cMsg =
client.ConfigService.AddSchedule(
this.ControllerBase.SessionVariables.Credentials,
schedule
);
return new ObjectCreateStatus(cMsg.Result, cMsg.Guid(?))
}
finally
{
client.Close();
}
}

Categories