I have a Website which has several aspx pages that derives from a PageBase class. For example one of that is below:
public partial class Pages_Home_Default : PageBase
{
}
In some of these pages, I would like to prevent access UNLESS logged in. I can get whether client is logged in or not in my PageBase with a IsMember property.
I would like to use attibutes to achive that. For example:
[AuthenticationRequired(true)]
public partial class Pages_Home_Default : PageBaseList
{
}
[AttributeUsage(AttributeTargets.Class)]
public class AuthenticationRequired : Attribute
{
public AuthenticationRequired(bool isMemberRequired)
{
Value = isMemberRequired;
}
public bool Value { get; private set; }
}
and in the PageBase for example:
protected override void OnPreInit(EventArgs e)
{
//Retrieve the AuthenticationRequired attribue value and if not authenticated Redirect client to a login page if logged in, continue displaying the page
}
I also found this to get and read the attribute
System.Reflection.MemberInfo info = typeof(Pages_Home_Default);
object[] attributes = info.GetCustomAttributes(true);
But this is not practical when you want to do it on the BASE class instead of the DERIVED one.
Can this be done?
Thank you very much
If your using MVC, there's an att for that - AuthorizeAttribute.
If your using WebForms then you don't need to use an attribute, you can control this from the web.config using the authorization element.
Why don't you check it in the attribute itself?
[AttributeUsage(AttributeTargets.Class)]
public class AuthenticationRequired : Attribute
{
public AuthenticationRequired(bool isMemberRequired)
{
if(isMemberRequired && !HttpContext.Current.User.Identity.IsAuthenticated)
{
FormsAuthentication.RedirectToLoginPage();
}
}
}
Ok. I combined the code I have given earlier with a simple line from other sources and here is the code I came up with:
[AttributeUsage(AttributeTargets.Class)]
public class AuthenticationRequired : Attribute
{
public AuthenticationRequired(bool isMemberRequired)
{
Value = isMemberRequired;
}
public bool Value { get; private set; }
}
public class Utility
{
public static T GetCustomAttribute<T>(Type classType) where T : Attribute
{
object Result = null;
System.Reflection.MemberInfo Info = classType;
foreach (var Attr in Info.GetCustomAttributes(true))
{
if (Attr.GetType() == typeof(T))
{
Result = Attr;
break;
}
}
return (T)Result;
}
}
public class PageBase : System.Web.UI.Page
{
protected override void OnPreInit(EventArgs e)
{
AuthenticationRequired AttrAuth = Utility.GetCustomAttribute<AuthenticationRequired>(this.GetType());
if (AttrAuth != null && AttrAuth.Value)
{
if(!IsMember)
HttpContext.Current.Response.Redirect("Membership.aspx");
}
}
}
Related
I have code like below. Interface with default implementation. And the user who uses this interface. But for some reason in the switch case my code uses the default implementation of the interface for the "Name' instead of the class implementation. What should i change to see "Ben" in console?
namespace ConsoleApp1
{
public interface IUser
{
// Interface with default implementation
public string Name { get => "Tom"; }
}
// User using this interface
public class BenUser : IUser
{
public string Name = "Ben";
}
public static class MainClass
{
public static void ShowName(IUser user)
{
switch (user.Name)
{
case "Ben": // I expected the code to run here
Console.WriteLine("Ben");
break;
case "Tom": // But the code goes here
Console.WriteLine("Tom");
break;
}
}
static void Main()
{
// Create a user with Name "Ben"
var ben = new BenUser();
ShowName(ben); // In console i see "Tom" for some reason
}
}
}
I can't figure out why the code is behaving like this.
As mentioned in comments, you need to implement the interface using the same shape in your class - as a property with a get.
public interface IUser
{
// Interface with default implementation
public string Name { get => "Tom"; }
}
// User using this interface
public class BenUser : IUser
{
public string Name { get => "Ben"; }
}
public static class MainClass
{
public static void ShowName(IUser user)
{
switch (user.Name)
{
case "Ben": // I expected the code to run here
System.Console.WriteLine("Ben");
break;
case "Tom": // But the code goes here
System.Console.WriteLine("Tom");
break;
}
}
static void Main()
{
// Create a user with Name "Ben"
var ben = new BenUser();
ShowName(ben); // In console i see "Tom" for some reason
}
}
This is my edit to show some more standard practices, please read through the comments and see if it makes anything more clear. The standard practice for creating members is to use accesslevel Type VariableName { get; set; }
namespace ConsoleApp1
{
public interface IUser
{
//denotes that this is set by construction, cannot be set afterwards
public string Name { get; }
}
// User using this interface
public class BenUser : IUser
{
// Standard 'getter' only member with a compiled return value
public string Name
{
get
{
return "Ben";
}
}
}
public class User : IUser
{
// private settable string to use with construction
private string _name;
// constructor
public User(string userName)
{
// sets the private variable to desired value
_name = userName;
}
// public 'getter' that returns the set value
public string Name
{
get
{
return _name;
}
}
}
public static class MainClass
{
public static void ShowName(IUser user)
{
Console.WriteLine(user.Name);
}
static void Main()
{
// Create a user with static Name "Ben"
var ben = new BenUser();
ShowName(ben);
// Create a user with variable Name set as "Carl"
var carl = new User("Carl");
ShowName(carl);
}
}
}
The Name in IUser is a property while Name in BenUser is a field. With your code when we do user.Name it calls the get method defined in IUser instead of getting value of Name field from BenUser. Here is a sample implementation for fixing your bug.
public class BenUser : IUser
{
public string Name { get => "Ben"; }
}
I would recommend to not do it the way you are doing because Name identifier has become embiguos
I am trying to create a custom attribute in console application but it is not working. My custom attribute never gets called. I found a good example here Custom Attribute not being hit
but not happy with its implementation.
I am wondering how data annotations works in MVC. we don't have to call it separately.
Is MVC calling those data annotations attribute behind the scene?
I wish to create custom attribute that I can use it on any class property same like data annotations attribute. But calling it separately like in above link is not what i am looking.
Here is what I have tried:
using System;
namespace AttributePractice
{
[AttributeUsage(AttributeTargets.Property)]
public class CustomMessageAttribute : Attribute
{
public static readonly CustomMessageAttribute Default = new CustomMessageAttribute();
protected string Message { get; set; }
public CustomMessageAttribute() : this(string.Empty)
{
Console.WriteLine("Default message is empty");
}
public CustomMessageAttribute(string message)
{
Message = message;
}
public string MyMessage =>
Message;
public override bool Equals(object obj)
{
if (obj == this)
return true;
if (obj is CustomMessageAttribute customMessageAttribute)
return customMessageAttribute.Message == MyMessage;
return false;
}
public override int GetHashCode()
{
return MyMessage.GetHashCode();
}
public override bool IsDefaultAttribute()
{
return Equals(Default);
}
}
public class Person
{
//This never works
// I am looking to use this attribute anywhere without calling it
// separately , same like data annotations
[CustomMessage("Hello world")]
public string Name { get; set; }
public int Age { get; set; }
public void DisplayPerson()
{
Console.WriteLine(Name);
Console.WriteLine(Age);
}
}
internal static class Program
{
private static void Main(string[] args)
{
var personObj = new Person
{
Name = "Tom",
Age = 28
};
personObj.DisplayPerson();
}
}
}
Can anybody tell me how to make my custom attribute works like data annotation way?
yes, if you need 10 custom attributes, you should create 10 separate.
There is tons of info about skipping Properties based on conditionals, but I would like to skip the entire object based on conditions within the object's class. I would like a solution that is contained within the object's class if at all possible. Keep in mind this is a collection of myObj that I am serializing.
public class myObj
{
bool conditional;
ShouldSerialize()
{
return conditional;
}
}
Or
public class myObj
{
[JsonCondition]
public bool conditional{get;}
}
Or even
[JsonCondition(typeof(MyConditionChecker))]
public class myObj
{
public bool conditional{get;}
}
class MyConditionChecker: JsonCondition
{
public override bool CanConvert(object sourceObj)
{
return (sourceObj as myObj).conditional;
}
}
What I got from your comments you would be best served creating your own wrapper around Json that applies the filtering.
public interface IConditionalSerializer
{
bool ShouldBeSerialized();
}
public static class FilteredSerializer
{
public static string SerializeConditional<T>(IEnumerable<T> input)
where T : IConiditionalSerializer
{
return JsonConvert.SerializeObject(input.Where(e => e.ShouldBeSerialized()));
}
}
public class Demo : IConditionalSerializer
{
public bool ShouldBeSerialized() => false;
}
You might also replace the interface with a reflection approach, but keep in mind the performance loss.
public interface IConiditionChecker
{
bool ShouldBeSerialized(object instance);
}
public class ConditionAttribute : Attribute
{
public Type ConditionChecker { get; set; }
}
public static class FilteredSerializer
{
public static string SerializeConditional(IEnumerable<object> input)
{
var matches = (from entry in input
let att = entry.GetType().GetCustomAttribute<ConditionAttribute>()
let hasChecker = att != null && att.ConditionChecker != null
let checker = hasChecker ? (IConiditionChecker)Activator.CreateInstance(att.ConditionChecker) : null
where checker.ShouldBeSerialized(entry)
select entry);
return JsonConvert.SerializeObject(matches);
}
}
[Condition(ConditionChecker = typeof(SomeChecker))]
public class Demo
{
}
Edit: Based on your comment you could do this. Only must decide wether to use opt-in or opt-out in the where-statement. It must ether be casted != null && casted.ShouldBeSerialized or what it currently says.
public interface IShouldBeSerialized
{
bool ShouldBeSerialized();
}
public static class FilteredSerializer
{
public static string SerializeConditional(IEnumerable<object> input)
{
var matches = (from entry in input
let casted = entry as IShouldBeSerialized
where casted == null || casted.ShouldBeSerialized()
select entry);
return JsonConvert.SerializeObject(matches);
}
}
public class Demo : IShouldBeSerialized
{
public bool ShouldBeSerialized()
{
return false;
}
}
If you're able to use the JSON.NET serializer, in terms of not serializing specific items within a collection, you could make the main collection non serializable, then add another filtered collection that does serialize.
public class Manager
{
[JsonIgnore]
public Employee[] Employees { get; set; }
[JsonProperty("Employees")]
public Employee[] SerializableEmployees
{
get { return Employees.Where(e => e.Name != "Bob").ToArray(); }
set { Employees = value; }
}
}
Alternatively, you could mark your class with the [JsonConverter] attribute and use a custom converter to check your condition. A similar approach that ignores a class entirely is detailed here.
I have a Part base class
class Part {
public PartType Type { get; set; }
}
with many implementations.
class Wire : Part { }
I have a TreeView in my program. And when I click on an element of it, I want a list to be filled with all the Parts of the Type I clicked in the TreeView.
When I have multiple lists open I want only those be loading the parts that have the same PartType as I clicked in the TreeView.
class BasePartListViewModel<T> : ListViewModel where T : Part {
protected override void OnTreeSelectionChanged(PartType type)
if (type == PartType.Wire) {
//load the Wires from the DB and display them
}
else {
//ignore the changed type event
}
}
}
But since this is a base class for all Parts by using T I would like to replace
if (_type == PartTypeEnum.Wire)
with something like
if (_type == T.Type)
but that does of course not work. How else?
Since the part type is a static information for a class type by design (am I right?), you could use an attribute to store it:
[AttributeUsage(AttributeTargets.Class)]
public class PartTypeAttribute : Attribute
{
public readonly PartType PartType;
public PartTypeAttribute(PartType partType)
{
PartType = partType;
}
}
Then apply it to the descendant classes:
[PartType(PartType.Wire)]
class Wire : Part
{
}
Then in the static constructor of the BasePartListViewModel class you can obtian the corresponding value:
class BasePartListViewModel<T> : ListViewModel
where T : Part
{
private static PartType PartTypeOfT;
static BasePartListViewModel()
{
var attr = typeof(T).GetCustomAttributes(typeof(PartTypeAttribute), true)
.FirstOrDefault() as PartTypeAttribute;
if (attr != null)
PartTypeOfT = attr.PartType;
}
protected override void OnTreeSelectionChanged(PartType type)
{
if (type == PartTypeOfT) {
....
}
}
}
If you do this.GetType() it will return as BasePartListViewModel`1[Wire]
You should not be ideally referring this in the base class.
I am working on a Asp.net MVC project and I am wondering if there is a way for the attributes to talk to other attributes.
For example, I have the following attributes
public class SuperLoggerAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Do something super
}
}
public class NormalLoggerAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
//Do something normal ONLY if the super attribute isn't applied
}
}
And I have the following controllers
[NormalLogger]
public class NormalBaseController : Controller
{
}
public class PersonController: NormalBaseController
{
}
[SuperLogger]
public class SuperController: NormalBaseControler
{
}
So basically, I want my SuperController to use SuperLogger and ignore NormalLogger (which was applied in the base), and PersonController should use the NormalLogger since it's not "overrided" by the SuperLogger. Is there a way to do that?
Thanks,
Chi
Why not just have SuperLoggerAttribute inherit from NormalLoggerAttribute and override the Log method?
I think this should work:
public enum LoggerTypes
{
Normal,
Super
}
public class LoggerAttribute : ActionFilterAttribute
{
public LoggerAttribute() : base()
{
LoggerType = LoggerTypes.Normal;
}
public LoggerAttribute(LoggerTypes loggerType) : base()
{
LoggerType = loggerType;
}
public LoggerTypes LoggerType
{
get;
set;
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (LoggerType == LoggerTypes.Super)
{
//
}
else
{
//
}
}
Usage:
[Logger(LoggerTypes.Normal)]
or
[Logger(LoggerTypes.Super)]