Check EF before changing view or URL MVC4 - c#

I need check my EF or values of certains data before changing view or url inside the app
I have a view where process import information to other wiew under controller, i need to check values before user changing to other view or want try other process inside the view (import information)
i will try under my button inside the view but is the user want change to other view the process not work...
The process under the button is this:
Controller:
public ActionResult Index(int? page, string filter, int id = 0)
{
ViewBag.OrderPurchaseID = id;
var check_import = db.OrderPurchaseDetails.Where(o => o.OrderPurchaseID == id && o.QtyTraslate > 0).ToList();
if (check_import.Count() > 0)
{
TempData["ErrorMessage"] = "You have articles pending to import, check or delete them";
return RedirectToAction("Edit", "OrderPurchase", new { id = id });
}
#region remember filter stuff
if (filter == "clear")
{
Session["Text"] = null;
Session["From"] = null;
Session["To"] = null;
}
else
{
if ((Session["Text"] != null) || (Session["From"] != null) || (Session["To"] != null))
{
return RedirectToAction("Search", new { text = Session["Text"], from = Session["From"], to = Session["To"] });
}
}
#endregion
var orderpurchases = db.OrderPurchases.Include(o => o.Provider);
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
return View(orderpurchases.OrderByDescending(p => p.TimeStamp).ToPagedList(currentPageIndex, defaultPageSize));
}
View:
#Html.ActionLink("List", "Index", new { id = Model.OrderPurchaseID }, new { #class = "btn" })
I need replicate this method to global level, if is possible of course...
Thanks for your help.

i use LogAttribute to check data in my EF from import data, thanks to Yuliam and Lee Winter for the help and bring me a solution global level.
public class LogAttribute : ActionFilterAttribute
{
private dbcAmerica db = new dbcAmerica();
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
int data = Convert.ToInt32(filterContext.Controller.TempData["id"]);
var checkIn = db.OrderPurchaseDetails.Where(o => o.QtyTraslate > 0 && o.OrderPurchaseID == data).ToList();
if (checkIn.Count() > 0)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary
{
{ "action", "Edit" },
{ "controller", "OrderPurchase" },
{ "id", data},
});
}
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
// ... log stuff after execution
}
}

Related

how to implement custom field with Audit.Net entityframework

I'm new to Audit.net. I successfully configure it in my project.
But now, i need to extend it to save extra information like requesterID and a comment write on the view page.
my case :
Entity mapped to Entity_AT
Entity {
[Key]
int ID
string label
}
Entity_AT {
[Key]
int ATID
int ID
string label
int ATFlag
datetime ATCreationDate
string RequesterID
string ATComment
}
public void Add(TEntity obj, string RequesterId)
{
_dbSet.Add(obj);
_context.SaveChanges();
}
[AuditDbContext(Mode = AuditOptionMode.OptOut, IncludeEntityObjects = false, AuditEventType = "{database}_{context}")]
public class MyDBContext : AuditIdentityDbContext<ApplicationUser>
{
}
Audit.Core.Configuration.DataProvider = new EntityFrameworkDataProvider()
{
AuditTypeMapper = t => t == typeof(Entity) ? typeof(Entity_AT) : null,
AuditEntityAction = (evt, entry, auditEntity) =>
{
var a = (dynamic)auditEntity;
a.ATCreationDate = DateTime.UtcNow;
a.ATFlag = (entry.Action == "Insert") ? 1 : (entry.Action == "Update") ? 2 : (entry.Action == "Delete") ? 3 : 0;
return true; // return false to ignore the audit
}
};
I tried :
_context.AddAuditCustomField("RequesterId", requesterId);
_context.AddAuditCustomField("ATComment", "pippo");
_dbSet.Add(obj);
_context.SaveChanges();
but no results
You have added the "RequesterId" custom field to the AuditEvent, but you are not mapping it to the AuditEntity property.
You should do the following on the entity action:
Audit.Core.Configuration.DataProvider = new EntityFrameworkDataProvider()
{
AuditTypeMapper = t => t == typeof(Entity) ? typeof(Entity_AT) : null,
AuditEntityAction = (evt, entry, auditEntity) =>
{
var a = (dynamic)auditEntity;
a.ATCreationDate = ...;
a.ATFlag = ...;
a.RequesterID = evt.CustomFields["RequesterId"] as string;
a.ATComment = evt.CustomFields["ATComment"] as string;
return true;
}
};
Note you can alternatively use the Fluent API to configure the data provider with a cleaner syntax:
Audit.Core.Configuration.Setup()
.UseEntityFramework(_ => _
.AuditTypeExplicitMapper(map => map
.Map<Entity, Entity_AT>((evt, entry, auditEntity) =>
{
auditEntity.ATCreationDate = ...;
auditEntity.ATFlag = ...;
auditEntity.RequesterID = evt.CustomFields["RequesterId"] as string;
auditEntity.ATComment = evt.CustomFields["ATComment"] as string;
})));

Xamarin.Forms: NavigationController is null in PageRenderer

I am trying to use PageRenderer to customize/reposition elements of ToolbarItem for iOS but here NavigationController throwing null reference exception.
Below my code
public class MyNavigationRenderer: PageRenderer
{
public new MyNavigationBar Element
{
get { return (MyNavigationBar)base.Element; }
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
var LeftNavList = new List<UIBarButtonItem>();
var rightNavList = new List<UIBarButtonItem>();
var navigationItem = this.NavigationController.TopViewController.NavigationItem;
for (var i = 0; i < Element.ToolbarItems.Count; i++)
{
var reorder = (Element.ToolbarItems.Count - 1);
var ItemPriority = Element.ToolbarItems[reorder - i].Priority;
if (ItemPriority == 1)
{
UIBarButtonItem LeftNavItems = navigationItem.RightBarButtonItems[i];
LeftNavList.Add(LeftNavItems);
}
else if (ItemPriority == 0)
{
UIBarButtonItem RightNavItems = navigationItem.RightBarButtonItems[i];
rightNavList.Add(RightNavItems);
}
}
navigationItem.SetLeftBarButtonItems(LeftNavList.ToArray(), false);
navigationItem.SetRightBarButtonItems(rightNavList.ToArray(), false);
}
}
Below MyNavigationBar.cs class in portable/shared forms project
public class MyNavigationBar : NavigationPage
{
public MyNavigationBar(Page content) : base(content)
{
Init();
}
private void Init()
{
this.ToolbarItems.Add(new ToolbarItem() { Icon = "kid", Priority = 0, Order = ToolbarItemOrder.Primary });
this.ToolbarItems.Add(new ToolbarItem() { Text = "License", Priority = 0, Order = ToolbarItemOrder.Primary });
}
}
App starting
public App ()
{
InitializeComponent();
MainPage = new MyNavigationBar(new LoginPage());
}
See below screenshot getting exception
I faced this issue, but in my case, I was trying to get NavigationController from content page which didn't had NavigationController, make sure you null check before calling TopViewController,
var navController = this.NavigationController;
if(navController == null)
{
return;
}
UINavigationItem navigationItem = navController.TopViewController.NavigationItem;
For example,
When User opens the app, he will be presented with Login page, which didn't had any Navigation Bar.

Views returned based on variable and existence

I have an asp.net-mvc website I am working on. The site is meant to as a basis for multiple clients all with their own unique business requirements. For any given controller method, I may or may not have a customized view for the client based on their ClientId.
Right now how I am handling this is through a ResourceSelectorObject like so:
public class ClientResourceSelector
{
public ClientResourceSelector(int clientId)
{
this.ClientId = clientId;
}
public int ClientId { get; set; }
public readonly List<ViewProfile> ViewProfiles = new List<ViewProfile>()
{
new ViewProfile { ClientId = 8, Controller = "Contact", Action = "NewContact", View = "C008/NewContact" }
};
public string ViewName(string controller, string action)
{
var Profile = ViewProfiles.FirstOrDefault(X => X.Controller.Equals(controller) && X.Action.Equals(action) && X.ClientId == ClientId);
if (Profile == null) return string.Empty;
return Profile.View;
}
}
Then in the code, I use that object in this manner:
// GET: Contact/NewContact
public ActionResult NewContact()
{
var selector = new ClientResourceSelector(ClientId);
string alternate_view = selector.ViewName("Contact", "NewContact");
if (String.IsNullOrEmpty(alternate_view))
return View(NewContactViewModel.Instance(ClientId));
else
return View(alternate_view, NewContactViewModel.Instance(ClientId));
}
The problem, and this is definitely the programming equivalent of "First World Problems," but I would like to still be able to just call View(viewModel) and have it select the appropriate view to display programmatically without my having to remember to register each view in the selector.
Obviously, I would then want to override the View() method in the abstract controller that all of my controllers are inheriting from. But I am unsure of how that code would look. Any suggestions would be helpful.
Here is how I've created ones in the past. Most of the Tenant systems I've built use some type of route/request parameter (could easily be updated to use DNS or wahtever, you have a lot of options) to determine the specific Tenant. I use an action filter that executes before any controller (or routing) to populate the route data (useful for Tenant specific routes as well).
public class TenantActionFilterAttribute : ActionFilterAttribute
{
internal const string _Tenant = "tenant";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Do this how ever you want, right now I'm using querystring
// Could be changed to use DNS name or whatever
var tenant = filterContext.HttpContext.Request.QueryString[_Tenant] as string;
if (tenant != null)
{
filterContext.RouteData.Values[Tenant] = tenant;
}
}
}
Either globally register the action filter:
RegisterGlobalFilters(GlobalFilters.Filters);
(Or using a Dependency Injection Framework)
Then a custom ViewEngine:
public class TenantViewEngine : RazorViewEngine
{
private string GetPrefix(ControllerContext controllerContext)
{
var result = string.Empty;
var tenant = controllerContext.RouteData.Values[TenantActionFilterAttribute.Tenant] as string;
if (!string.IsNullOrEmpty(tenant))
{
result = "Tenants/" + tenant + "/";
}
return result;
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
var prefix = GetPrefix(controllerContext);
if (partialPath.StartsWith("~/"))
{
partialPath = partialPath.Insert(2, prefix);
}
else if (partialPath.StartsWith("~") || partialPath.StartsWith("/"))
{
partialPath = partialPath.Insert(1, prefix);
}
else if (string.IsNullOrEmpty(partialPath))
{
partialPath = prefix + partialPath;
}
return base.CreatePartialView(controllerContext, partialPath);
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
var prefix = GetPrefix(controllerContext);
if (viewPath.StartsWith("~/"))
{
viewPath = viewPath.Insert(2, prefix);
}
else if (viewPath.StartsWith("~") || viewPath.StartsWith("/"))
{
viewPath = viewPath.Insert(1, prefix);
}
else if (!string.IsNullOrEmpty(viewPath))
{
viewPath = prefix + viewPath;
}
if (masterPath.StartsWith("~/"))
{
masterPath = masterPath.Insert(2, prefix);
}
else if (masterPath.StartsWith("~") || masterPath.StartsWith("/"))
{
masterPath = masterPath.Insert(1, prefix);
}
else if (!string.IsNullOrEmpty(masterPath))
{
masterPath = prefix + masterPath;
}
return base.CreateView(controllerContext, viewPath, masterPath);
}
}
I can't exactly remember how this works, but the search paths change from the default to something very close to:
"~/Tenants/<TenantName>/Areas/{3}/Views/{1}/{0}.cshtml",
"~/Areas/{3}/Views/{1}/{0}.cshtml",
"~/Tenants/<TenantName>//Views/{1}/{0}.cshtml",
"~/Views/{1}/{0}.cshtml",
"~/Tenants/<TenantName>//Views/Shared/{0}.cshtml",
"~/Views/Shared/{0}.cshtml",
Where 1:Controller, 2:View/Action, 3:AreaName

Making a method more generic ASP MVC

I have an Index Method in my FileController that can return a file that is stored in the Attachments entity. How can I change the method to work with any entity not just the Attachments?
public class FileController : Controller
{
private MainDatabaseContext db = new MainDatabaseContext();
// GET: File
public ActionResult Index(int id)
{
var fileToRetrieve = db.Attachments.Find(id);
var FileObject= File (fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
}
This is what I have done as a workaround, but it has a lot of repeated code which I wanted to avoid:
public class FileController : Controller
{
private MainDatabaseContext db = new MainDatabaseContext();
enum EntityName
{
Attachment=1,
WAProgramApplicationId,
HouseholdIncome,
HouseholdMember
}
// GET: File
public ActionResult Index(int id=0,int WAProgramApplicationId=0,int householdIncomeID=0,int householdMemberId=0)
{
if (householdIncomeID!=0)
{
return GetFileObject(householdIncomeID, EntityName.HouseholdIncome);
}
if (id!=0)
{
return GetFileObject(id, EntityName.Attachment);
}
if (WAProgramApplicationId != 0)
{
return GetFileObject(WAProgramApplicationId, EntityName.WAProgramApplicationId);
}
if (householdMemberId!=0)
{
return GetFileObject(householdMemberId, EntityName.HouseholdMember);
}
return null;
}
private ActionResult GetFileObject(int id, EntityName entityName)
{
if (entityName==EntityName.Attachment)
{
var fileToRetrieve = db.Attachments.Find(id);
var FileObject = File(fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
if (entityName == EntityName.HouseholdIncome)
{
var fileToRetrieve = db.HouseholdIncomes.Find(id);
var FileObject = File(fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
if (entityName==EntityName.WAProgramApplicationId)
{
var fileToRetrieve = db.WAProgramApplications.Find(id);
var FileObject = File(fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
if (entityName==EntityName.HouseholdMember)
{
var fileToRetrieve = db.HouseholdMembers.Find(id);
var FileObject = File(fileToRetrieve.AttachmentObject, fileToRetrieve.ContentType);
if (FileObject.FileDownloadName.Length == 0)
{
FileObject.FileDownloadName = fileToRetrieve.Filename;
}
return FileObject;
}
return null;
}
}
to make the entity more generic just use the Set method, you can do it like this:
db.Set<YourEntity>().Find(id);
They are some approaches how to implement a generic controller with data.
Check here and here.
If you have a repository that can handle _repository.get<T> and return the right object, you can achieve this.

HTML.textBoxFor(x=>x.Price, disabled = true) doesn't post the value to the controller post action!

Asp .net MVC 3 application...
This is the View:
Grupa: <%= Html.DropDownListFor(x => x.Grupa, Model.ListaGrupe) %>
Produsul: <%= Html.DropDownListFor(x => x.Produs, Model.ListaProduse) %>
Cantitate: <%=Html.TextBoxFor(x => x.Cantitate, new { style = "width: 100px;" })%>
Pret: <%=Html.TextBoxFor(x => x.Pret, new { style = "width: 100px;", disabled = true})%>
TVA: <%= Html.TextBoxFor(x => x.TVA, new { style = "width: 100px;", disabled = true })%>
Valoare: <%= Html.TextBoxFor(x => x.NoTVA, new { style = "width: 120px;", disabled = true})%>
Valoare cu TVA: <%=Html.TextBoxFor(x => x.Total, new { style = "width: 120px;", disabled = true})%>
I am using some JQuery to change Pret, TVA, NoTVA and Total based on the values in Grupa, Produs and Cantitate so I don't want the user to modify the values inside them.
Probably disabled = true shoudn't be used. Then how can I make so the user can't modify the fields but the value to be posted to the controller's action?
You can also make them readonly rather than disabling them. On the other note, I think #Chris solution is better, that way your modified data will be posted back.
You can use Html.HiddenFor() and use a <span> or <div> instead. Their values will then be posted back.
Well, this is what i did up to now,
i didn't succeed to make a good, easy to use, readonly protection using encryption,
but i did manage to do something that i think might just do.
how it works:
When you use LockObject(o) an object, itterate the properties that have defined ProtectedAttribute defined for.
add the locked value to a list, specially made for this field.
! the list is kept in the user session (on the server side)
when the user submits the form, IsValid checks to see if the value is in the list of locked values. if yes, then it is all ok. otherwise, it must have been changed somehow.
! the number of values is not that big, and is temporary to the session, but if it is bothering someone, a simple lockList.remove(node); can easly be added when a value is validated.
Note: this can cause problem when the user uses Back buttons or Resubmit a form using Refresh.
tell me if you find any problems that this model does not take into account...
+ the Equalization is very naive, so it works only with value-types for time be.
Code:
Created an attribute named ProtectedAttribute:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public class ProtectedPropertyAttribute : ValidationAttribute
{
private static Dictionary<string, LinkedList<object>> savedValues;
static ProtectedPropertyAttribute()
{
savedValues = (Dictionary<string, LinkedList<object>>)HttpContext.Current.Session["ProtectedAttributeData"];
if (savedValues != null)
return;
savedValues = new Dictionary<string, LinkedList<object>>();
HttpContext.Current.Session.Add("ProtectedAttributeData", savedValues);
}
public static void LockObject(object obj)
{
Type type = obj.GetType();
foreach (PropertyInfo property in type.GetProperties())
{
LockProperty(obj, property);
}
}
public static void LockProperty(object obj, PropertyInfo property)
{
ProtectedPropertyAttribute protectedAttribute =
(ProtectedPropertyAttribute)
property.GetCustomAttributes(typeof (ProtectedPropertyAttribute), false).FirstOrDefault();
if (protectedAttribute == null)
return;
if(protectedAttribute.Identifier == null)
protectedAttribute.Identifier = property.Name;
LinkedList<object> list;
if (!savedValues.TryGetValue(protectedAttribute.Identifier, out list))
{
list = new LinkedList<object>();
savedValues.Add(protectedAttribute.Identifier, list);
}
list.AddLast(property.GetValue(obj, null));
}
public string Identifier { get; set; }
public ProtectedPropertyAttribute()
{
}
public ProtectedPropertyAttribute(string errorMessage) : base(errorMessage)
{
}
public ProtectedPropertyAttribute(Func<string> errorMessageAccessor) : base(errorMessageAccessor)
{
}
protected override ValidationResult IsValid (object value, ValidationContext validationContext)
{
LinkedList<object> lockedValues;
if (Identifier == null)
Identifier = validationContext.DisplayName;
if (!savedValues.TryGetValue(Identifier, out lockedValues))
return new ValidationResult(FormatErrorMessage(validationContext.MemberName), new[] { validationContext.MemberName });
bool found = false;
LinkedListNode<object> node = lockedValues.First;
while (node != null)
{
if(node.Value.Equals(value))
{
found = true;
break;
}
node = node.Next;
}
if(!found)
return new ValidationResult(FormatErrorMessage(validationContext.MemberName), new[] { validationContext.MemberName });
return ValidationResult.Success;
}
}
place this attribute on any property of your model just as any other validation.
public class TestViewModel : Controller
{
[ProtectedProperty("You changed me. you bitch!")]
public string DontChangeMe { get; set; }
public string ChangeMe { get; set; }
}
in the controller, after you are finished with the viewmodel object,
you call ProtectedAttribute.LockObject(myViewModel)
public class TestController : Controller
{
public ActionResult Index()
{
TestViewModel vm = new TestViewModel {ChangeMe = "a1", DontChangeMe = "b1"};
ProtectedPropertyAttribute.LockObject(vm);
return View(vm);
}
public string Submit(TestViewModel vm)
{
string errMessage;
return !validate(out errMessage) ? "you are a baaad, man." + errMessage : "you are o.k";
}
private bool validate(out string errormessage)
{
if (ModelState.IsValid)
{
errormessage = null;
return true;
}
StringBuilder sb = new StringBuilder();
foreach (KeyValuePair<string, ModelState> pair in ModelState)
{
sb.Append(pair.Key);
sb.Append(" : <br/>");
foreach (ModelError err in pair.Value.Errors)
{
sb.Append(" - ");
sb.Append(err.ErrorMessage);
sb.Append("<br/>");
}
sb.Append("<br/>");
}
errormessage = sb.ToString();
return false;
}
}

Categories