UPDATE: I completely reformulated the question
I am trying to implement an algorithm that would change the class name dynamically.
For Example:
Data.cs
public class Data
{
public string text1 { get; set; }
public string text2 { get; set; }
}
User1.ascx
public partial class User1 : System.Web.UI.UserControl
{
public Data datas = new Data();
}
User2.ascx
public partial class User2 : System.Web.UI.UserControl
{
public Data datas = new Data();
}
User.aspx
public partial class User: System.Web.UI.Page
{
[WebMethod]
public static string RequestUC(Data datas)
{
if (datas.userfile = "User1.ascx")
{
User1 userControl = (User1)page.LoadControl(datas.userfile);
}
else
{
User2 userControl = (User2)page.LoadControl(datas.userfile);
}
using (Page page = new Page())
{
userControl.datas = datas; // the error says that the userControl not recognized
page.Controls.Add(userControl);
using (StringWriter writer = new StringWriter())
{
page.Controls.Add(userControl);
HttpContext.Current.Server.Execute(page, writer, false);
return writer.ToString();
}
}
}
}
The problem is I can't get the User.aspx work. Any solutions would work.
How can I use generics in this case?
thank YOU
Use inheritance.
Create a base user control class:
public abstract class UserControlBase : System.Web.UI.UserControl {
public abstract Data Datas { get; set; }
}
Then derive each user control from that class (and implement the abstract properties, not shown):
public partial class User1 : UserControlBase
public partial class User2 : UserControlBase
And in your web method:
//TODO - validate that datas.userfile is appropriate
UserControlBase myControl = page.LoadControl(datas.userfile);
Related
I'm looking for a reliable solution to log details of requests and responses made to and from our controllers. However, some of the data passing through contains sensitive information that should not be written to a log.
In the controller, the inbound request is bound to a single model from the request body, and as the request is answered, a single model is passed to the Ok() result like this (very simplified):
[HttpGet]
[Route("Some/Route")]
public IHttpActionResult SomeController([FromBody] RequestType requestObj)
{
ResponseType responseObj = GetResponse(requestObj)
return this.Ok(responseObj);
}
Now my goal is to somehow log the contents of the request and response object at the beginning and end of the controller, respectively. What I would like to do is bind the models first, then log out their attributes. An example of the RequestType is something like:
public class RequestType
{
public string SomeAttribute { get; set; }
public string AnotherAttribute { get; set; }
public string Password{ get; set; }
}
And the log would look something like:
[date-time] Request to SomeController:
SomeAttribute: "value_from_request"
AnotherAttribute: "another_value"
Password: "supersecret123"
Now clearly we don't want the password to be logged. So I would like to create a custom data annotation that would not log certain fields. Its use would look like this (updated RequestType):
public class RequestType
{
public string SomeAttribute { get; set; }
public string AnotherAttribute { get; set; }
[SensitiveData]
public string Password{ get; set; }
}
Where would I start with this? I'm not incredibly familliar with .NET, but know that there are many sort of magic classes that can be subclassed to override some of their functionality. Is there any such class that can help here? Even better, is there any way to do this during the model binding? So we could catch errors that occur during model binding as well?
We should be able to achieve what you're looking for with an ActionFilterAttribute.
Capture Requests Attribute
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class CaptureRequestsAttribute : ActionFilterAttribute // *IMPORTANT* This is in the System.Web.Http.Filters namespace, not System.Web.Mvc
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var messages = actionContext.ActionArguments.Select(arg => GetLogMessage(arg.Value));
var logMessage = $"[{DateTime.Now}] Request to " +
$"{actionContext.ControllerContext.Controller}]:\n{string.Join("\n", messages)}";
WriteToLog(logMessage);
base.OnActionExecuting(actionContext);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var result = actionExecutedContext.Response.Content as ObjectContent;
var message = GetLogMessage(result?.Value);
var logMessage = $"[{DateTime.Now}] Response from " +
$"{actionExecutedContext.ActionContext.ControllerContext.Controller}:\n{message}";
WriteToLog(logMessage);
base.OnActionExecuted(actionExecutedContext);
}
private static void WriteToLog(string message)
{
// todo: write you logging stuff here
}
private static string GetLogMessage(object objectToLog)
{
if (objectToLog == null)
{
return string.Empty;
}
var type = objectToLog.GetType();
var properties = type.GetProperties();
if (properties.Length == 0)
{
return $"{type}: {objectToLog}";
}
else
{
var nonSensitiveProperties = type
.GetProperties()
.Where(IsNotSensitiveData)
.Select(property => $"{property.Name}: {property.GetValue(objectToLog)}");
return string.Join("\n", nonSensitiveProperties);
}
}
private static bool IsNotSensitiveData(PropertyInfo property) =>
property.GetCustomAttributes<SensitiveDataAttribute>().Count() == 0;
}
Sensitive Data Attribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class SensitiveDataAttribute : Attribute
{
}
Then, you can just add it to your WebApi controller (or a specific method in it):
[CaptureRequests]
public class ValuesController : ApiController
{
// .. methods
}
And finally your models can just add the SensitiveDataAttribute:
public class TestModel
{
public string Username { get; set; }
[SensitiveData]
public string Password { get; set; }
}
This does not make use of DataAnnotations,however, One way that comes to mind would be to use the serialization. If your payload is within a reasonable size you could serialize and deserialize your RequestType class when reading and writing to/from a log. This would require a custom serialization format or making use of the default, xml.
[Seriliazeble()]
public class RequestType
{
public string SomeAttribute { get; set; }
public string AnotherAttribute { get; set; }
[NonSerialized()]
public string Password{ get; set; }
}
Using the above attribute will omit Password from serialization. Then you copuld proceed to Logger.Log(MySerializer.Serialize(MyRequest)); and your sensitive data will be omitted.
This link describes the approach in detail.
For xml serialization, simply use the XmlSerializer class.
public class MySerializationService
{
public string SerializeObject(object item)
{
XmlSerializer serializer = new XmlSerializer(item.GetType());
System.IO.MemoryStream aMemStr = new System.IO.MemoryStream();
System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(aMemStr, null);
serializer.Serialize(writer, item);
string strXml = System.Text.Encoding.UTF8.GetString(aMemStr.ToArray());
return strXml;
}
public object DeSerializeObject(Type objectType, string objectString)
{
object obj = null;
XmlSerializer xs = new XmlSerializer(objectType);
obj = xs.Deserialize(new StringReader(objectString));
return obj;
}
}
Then using the above or similar methods you can read and write in a custom format.
Write :
string logData=new MySerializationService().SerializeObject(myRequest);
Read :
RequestType loggedRequest= (RequestType)new MySerializationService().DeSerializeObject(new RequestType().GetType(), logData);
TLDR: In Asp Mvc 6 how do I perform model validation with a service using data annotations? What are the alternatives?
I have a very simple model
public class MyModel
{
[Required]
public string Name { get; set; }
}
I also have a service that exposes some simple validation methods
public interface IMyService
{
string[] ReservedWords { get; }
bool IsValidName(string name);
// Internally calls IsValidName and throws an Exception if the name is invalid
void Save(MyModel myModel);
// ... snip
}
And I have wired up my controller like so
public class MyController : Controller
{
private readonly IMyService _service;
public MyController(IMyService service)
{
_service = service;
}
// ... snip
public IActionResult Post(MyModel myModel)
{
if (!_service.IsValidName(input?.Name))
{
ModelState.AddModelError(nameof(MyModel.Name), "Invalid Name");
}
if (!ModelState.IsValid)
{
return View(myModel);
}
_service.Save(myModel);
return RedirectToAction(nameof(Index));
}
}
It feels a bit clucky to have 2 stages of validation - automatic model validation then manually performing service validation. I was hoping that something simialr to this would work
public class MyModel
{
[ServiceValidation(nameof(IMyService), nameof(IMyService.IsValidName)]
[Required]
public string Name { get; set; }
}
public ServiceValidationAttribute : ValidationAttribute
{
private readonly Type _interfaceOrClass;
private readonly string _methodOrProperty;
public ServiceValidationAttribute(Type interfaceOrClass, string methodOrProperty)
{
_interfaceOrClass = interfaceOrClass;
_methodOrProperty = methodOrProperty;
}
public override bool RequiresValidationContext => true;
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var service = validationContext.GetService(_interfaceOrClass);
// Extension method in shared library to assist with reflection
bool isValid = _interfaceOrClass.ValueForMethodOrPropertyNamed<bool>(service, _methodOrProperty, value);
return isValid
? ValidationResult.Success
: new ValidationResult(ErrorMessage);
}
}
However var serivce is always null, is there any way around this? I have wired up the IMyService to an implementation in the Startup.cs as it is available in the Controller.
Alternatively is there a better way of adding to the ModelState with a service?
I'm new to MVC 5 with .net
Basically I'm just trying to get my bearings and I want to display some generic queries (disregard the fact that im using the master db, I just want to get the functions working right now). I'm using the authentication 2.0 which has an applicatindbcontext, but I created my own context but since I'm not really wanting to create a model (which could be the problem) I didn't know what to create for properties:
public class MasterModel : DbContext
{
public MasterModel() : base("MasterDatabaseConnection")
{ }
}
I created the controller like:
public class MasterController : Controller
{
private MasterModel db = new MasterModel();
// GET: Statistics
public ActionResult Index()
{
return View();
}
public ActionResult GetVersion()
{
string query = "SELECT ##VERSION AS Version";
IEnumerable<MasterModel> data = db.Database.SqlQuery<MasterModel>(query);
return View(data.ToList());
}
}
And finally I'm trying to figure out how to display the results in the view...and I'm completely lost (although it's possible I was lost in one of the previous steps).
#model IEnumerable<IdentitySample.Models.MasterModel>
#{
ViewBag.Title = "Index";
}
#WTF.Am.I.SupposedToPutHere
I've followed some tutorials where I've created CRUD style model view controllers, but I guess I'm not drawing the connection on how to just submit informational queries and display the results.
Create a Context:
public class MasterModel : DbContext
{
public MasterModel() : base("MasterDatabaseConnection")
{ }
public DbSet<MyModel> ModelOBJ { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ModelOBJ>().ToTable("tblModelOBJ");
}
}
Create a Model:
Public cLass MyModel
{
public int ID {get;set;}
public string Name {get;set;}
}
Public cLass MyModelRepository
{
public List<MyModel> GetALlModelFromDB()
{
MasterModel md = new MasterModel();
return md.ModelTosend.toList();
}
}
In your Controller:
public ActionResult Index()
{
return View(new MyModelRepository().GetALlModelFromDB());
}
In your View:
#model IEnumerable<IdentitySample.Models.MyModel>
#{
ViewBag.Title = "Index";
}
#foreach(var item in Model)
{
#:<div>#item.ID #item.Name </div>
}
Can anybody suggest me how bind a dropdown list in MVC Razor view. I am using MVC 4. I have a view that is not bound with any model class.
public class Util {
public List<EmployeeType> GetEmpTypes() {
return (new List<EmployeeType>(){
new EmployeeType(){ID=101, Text="Permanent"},
new EmployeeType(){ ID=102, Text="Temporary"}
});
}
}
public class EmployeeType {
public int ID { get; set; }
public string Text { get; set; }
}
I have this sample code. I am new to MVC Now after this I don't know how to bind the collection returned by GetEmployeeTypes() Method to a dropdown list
Your class with method
public class Util {
public List<EmployeeType> GetEmpTypes() {
return (new List<EmployeeType>(){
new EmployeeType(){ID=101, Text="Permanent"},
new EmployeeType(){ ID=102, Text="Temporary"}
});
}
}
Your model class with properties
public class EmployeeType {
public int ID { get; set; }
public string Text { get; set; }
}
This is sample action
public ActionResult ViewName()
{
Util xxx=new Util();
List<SelectList> SelectedItems =new List<SelectList>();
List<EmployeeType> items =xxx.GetEmpTypes();
foreach (var t in items )
{
SelectListItem s = new SelectListItem();
s.Text = t.Text;
s.Value = t.ID;
SelectedItems.Add(s);
}
ViewBag.xxxxx= SelectedItems;
return view();
}
In View
#Html.DropDownList("xxxxx", new SelectList(ViewBag.xxxxx, "Text", "Value"))
This above code just like a key, i don't tested for that code ran successfully. you can get some idea for how to bind dropdown from my code.
I had a Class like this to get all EmployeeTypes
public class Util
{
public List<EmployeeType> GetEmpTypes()
{
return (new List<EmployeeType>(){
new EmployeeType(){ID=101, Text="Permanent"},
new EmployeeType(){ ID=102, Text="Temporary"}
});
}
}
public class EmployeeType
{
public int ID { get; set; }
public string Text { get; set; }
}
In Controller I have written code to get the List of Employee Types
Util obj = new Util();
var v = obj.GetEmpTypes();
ViewBag.EmployeeTypes = v;
return View();
In the View I have written code to bind dropdown.
#Html.DropDownList("EmployeeTypes",new SelectList(ViewBag.EmployeeTypes,"ID","Text"));
Thanks #Ramesh Rajendran ( Now I understood the concept to bind dropdown)
*strong text*you should create the model selectlist like here:
public static List<EmployeeType> GetEmpTypes() {
return (new List<EmployeeType>(){
new EmployeeType(){ID=101, Text="Permanent"},
new EmployeeType(){ ID=102, Text="Temporary"}
});
}
public static SelectList GetMyEmpTypes
{
get { return new SelectList(GetEmpTypes(), "ID", "Text"); }
}
then you access this method in dropdown list like
#Html.DropDownList("Name",yourProjectNameSpace.Util.GetMyEmpTypes())
when you will submit your form then it value bidden with Name get post to controller.
it is not necessary to bind with model class.you can receive the value on controller with the name that you have given in view like:
#Html.DropDownList("Name",yourProjectNameSpace.YourClass.GetEmpTypes())
Now you can recive the name value at controller like:
public ActionResult test(String Name)
{
return view();
}
and make your method static i.e GetEmpTypes() so that you can access it from view.
I have a base controller:
Public MustInherit Class InjuredWorkerController(Of TManager As IInjuredWorkerManagerBase)
Then I have a home controller:
Public Class HomeController
Inherits InjuredWorkerController(Of IInjuredWorkerManager)
IInjuredWorkerManager inherits IInjuredWorkerManagerBase
Why does this throw a cast exception:
Dim manager = CType(filterContext.Controller, InjuredWorkerController(Of IInjuredWorkerManagerBase)).Manager
Unable to cast object of type 'MyClaim.Controllers.HomeController' to type 'MyClaim.Controllers.InjuredWorkerController`1[SAIF.Web.Mvc.MyClaim.IInjuredWorkerManagerBase]'.
You need to extract an interface for your InjuredWorkerController to make it work, since co- and contravariance only works with interfaces and delegates.
This code compiles and runs (C# console app, I'm not fluent in VB.Net...):
using System;
namespace TestApplication
{
public interface IInjuredWorkerController<out TManager>
where TManager : IInjuredWorkerManagerBase
{
TManager Manager { get; }
}
public abstract class InjuredWorkerController<TManager>
: IInjuredWorkerController<TManager>
where TManager : IInjuredWorkerManagerBase, new()
{
protected InjuredWorkerController()
{
Manager = new TManager();
}
public TManager Manager { get; private set; }
}
public interface IInjuredWorkerManagerBase
{
string Name { get; }
}
public interface IInjuredWorkerManager
: IInjuredWorkerManagerBase {}
public class InjuredWorkerManager : IInjuredWorkerManager
{
public string Name
{
get { return "Homer"; }
}
}
public class HomeController
: InjuredWorkerController<InjuredWorkerManager> {}
internal class Program
{
private static void Main()
{
var controller = new HomeController();
var manager = ((IInjuredWorkerController<IInjuredWorkerManagerBase>)controller).Manager;
Console.Out.WriteLine(manager.Name);
Console.ReadKey();
}
}
}
Eric Lippert's blog series on the subject is a must read.