custom condition method attributes in C# - methods

I'm wondering if I can do something like this in c#:
public CustomerManagerScreen()
{
[TestAttirubute("CustomerManagerScreen_Load")]
private void CustomerManagerScreen_Load(object sender, EventArgs e)
{
CustomerLoad();
}
}
as you can see, method name is a parameter of TestAttribute, what I want to achieve is CustomerManagerScreen_Load will be discarded depending on the result of the TestAttirubute
this is the attribute class...
public class TestAttirubute: System.Attribute
{
private string _MethodName = string.Empty;
public TestAttirubute(string MethodName)
{
this._MethodName = MethodName;
}
public bool hasPermission()
{
return (SessionManager.CurrentUser.UserRole.Role.Rights.Where(a => a.Resource.Code == this._MethodName).Count() != 0) ? true: false;
}
}

Not like that, but with the ConditionalAttribute you can.
One restriction however is that your methods must return void.

Related

Is PropertyChanged += LinkLabel_PropertyChanged; same as protected override void OnPropertyChanged(string propertyName = null)

In a Xamarin template like this. I think there are two ways to check if a property has changed.
Adding PropertyChanged += LinkLabel_PropertyChanged;
Overriding, calling base
If I want to do something when more than one property has changed is there any difference between these two ways of calling a method?
public class LinkLabel : Label
{
public LinkLabel()
{
PropertyChanged += LinkLabel_PropertyChanged;
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
// Check property name and do action here
}
private void LinkLabel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// Check property name and do action here
}
}
For reference here is what I coded and I am wondering if that's a good solution:
public class LinkLabel : Label
{
public LinkLabel()
{
SetDynamicResource(Label.FontFamilyProperty, "Default-Regular");
SetDynamicResource(Label.FontSizeProperty, "LabelTextFontSize");
SetDynamicResource(Label.TextColorProperty, "LinkLabelColor");
VerticalOptions = LayoutOptions.CenterAndExpand;
VerticalTextAlignment = TextAlignment.Center;
}
public static readonly BindableProperty IsImportantProperty =
BindableProperty.Create(nameof(IsImportant), typeof(bool), typeof(LinkLabel), false);
public bool IsImportant
{
get { return (bool)GetValue(IsImportantProperty); }
set { SetValue(IsImportantProperty, value); }
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == IsEnabledProperty.PropertyName ||
propertyName == IsImportantProperty.PropertyName)
{
if (this.IsEnabled) {
if (this.IsImportant)
this.SetDynamicResource(Label.TextColorProperty, "LinkLabelImportantColor");
else
this.SetDynamicResource(Label.TextColorProperty, "LinkLabelColor");
}
else
this.SetDynamicResource(Label.TextColorProperty, "LinkLabelDisabledColor");
}
}
}
Yes, the difference is that registering for the PropertyChanged event works from outside, overriding the protected(!) OnPropertyChanged method works only from within derived classes of Label.
So you would normally only create a new derived LinkLabel class if you want to change the behavior of the label. There, you'd override the OnPropertyChanged (if you need to).
If you want to get informed about a change in your main form, you would register the event directly there. No need to create a derived class.

PostSharp - args.ReturnValye = default(T) -> T = method return type, how?

My aspect:
[Serializable]
class FlowController : OnMethodBoundaryAspect
{
[ThreadStatic]
private static bool logging;
public override void OnEntry(MethodExecutionArgs args)
{
if (logging)
return;
try
{
logging = true;
if (ProgramState.State() == false)
{
args.ReturnValue = ""; // WHAT DO I SET HERE?
args.FlowBehavior = FlowBehavior.Return;
}
}
finally
{
logging = false;
}
}
}
Basically the ProgramState.State() method checks if the program is running(true),paused(loops while isPaused == true), stopped(false), this should control the if methods can run or not(basically a start pause/resume stop thing)
But sometimes i get nullreferences when returning from the method.
i am interested in knowing how can i set the return type to the default return type of the method.
It is tested with PostSharp 6.0.29
Before use it please check required null controls.
If method is async Task
public override void OnException(MethodExecutionArgs args)
{
var methodReturnType = ((System.Reflection.MethodInfo)args.Method).ReturnType;
var runtime = methodReturnType.GetRuntimeFields().FirstOrDefault(f => f.Name.Equals("m_result"));
//Only if return type has parameterless constructture (should be check before create)
var returnValue = Activator.CreateInstance(runtime.FieldType);
args.ReturnValue = returnValue;
}
And if method is not async
public override void OnException(MethodExecutionArgs args)
{
var methodReturnType = ((System.Reflection.MethodInfo)args.Method).ReturnType;
//Only if return type has parameterless constructture (should be check before create)
var returnValue = Activator.CreateInstance(methodReturnType);
args.ReturnValue = returnValue;
}
You can make your aspect class generic with the generic parameter representing the method return type. Then you need to create a method-level attribute that is also an aspect provider. The attribute will be applied to the user code and in turn it can provide the correct instance of the generic aspect.
[Serializable]
[MulticastAttributeUsage( MulticastTargets.Method )]
public class FlowControllerAttribute : MethodLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects(object targetElement)
{
MethodInfo method = (MethodInfo) targetElement;
Type returnType = method.ReturnType == typeof(void)
? typeof(object)
: method.ReturnType;
IAspect aspect = (IAspect) Activator.CreateInstance(typeof(FlowControllerAspect<>).MakeGenericType(returnType));
yield return new AspectInstance(targetElement, aspect);
}
}
[Serializable]
public class FlowControllerAspect<T> : IOnMethodBoundaryAspect
{
public void RuntimeInitialize(MethodBase method)
{
}
public void OnEntry(MethodExecutionArgs args)
{
args.ReturnValue = default(T);
args.FlowBehavior = FlowBehavior.Return;
}
public void OnExit(MethodExecutionArgs args)
{
}
public void OnSuccess(MethodExecutionArgs args)
{
}
public void OnException(MethodExecutionArgs args)
{
}
}
// Usage:
[FlowController]
public int Method()
{
// ...
}

Chain CollectionChanged Events

I'm trying to see how it would be possible to chain together x number of ObservableCollections.CollectionChanged event, exposed as a N level depth object tree to a single parent level CollectionChanged event that consumers can listen to? Essentially I want to funnel or bubble all child CollectionChanged events up to the top most parent. A number of solution I've noticed that tackle similar issues make an assumption of a fixed number of levels, say 2 deep. I idea is to support any level of depth.
Originally I had hoped I could just pass the instance of the FieldInfos to the child constructors and attach directly to the handler. However i get an error stating the "Event 'CollectionChanged' can only appear on the left hand side of+= or -=.
Thanks,
public class FieldInfos
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
private ObservableCollection<Field> _fields;
public ObservableCollection<Field> Fields => _fields ?? (_fields = new ObservableCollection<Field>());
}
public class Field
{
public string Name;
private ObservableCollection<FieldInstance> _instances;
public ObservableCollection<FieldInstance> Instances => _instances ?? (_instances = new ObservableCollection<FieldInstance>());
}
public class FieldInstance
{
public string Id { get; set; }
}
The simplest approach is subclass the original ObservableCollection<T>.
You'd need at least one interface to avoid covariance problems. You can also have your own classes to implement the INotifyDescendantsChanged interface.
public interface INotifyDescendantsChanged
{
event NotifyCollectionChangedEventHandler DescendantsChanged;
}
public class ObservableBubbleCollection<T> : ObservableCollection<T>, INotifyDescendantsChanged
{
public event NotifyCollectionChangedEventHandler DescendantsChanged;
protected virtual void OnDescendantsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
NotifyCollectionChangedEventHandler handler = DescendantsChanged;
if (handler != null)
handler(sender, e);
}
private readonly Func<T, INotifyDescendantsChanged> childSelector;
public ObservableBubbleCollection() { }
public ObservableBubbleCollection(Func<T, INotifyDescendantsChanged> childSelector)
{
this.childSelector = childSelector;
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
base.OnCollectionChanged(e);
OnDescendantsChanged(this, e);
if (childSelector == null)
return;
if (e.NewItems != null)
foreach (var item in e.NewItems.Cast<T>())
childSelector(item).DescendantsChanged += OnDescendantsChanged;
if (e.OldItems != null)
foreach (var item in e.OldItems.Cast<T>())
childSelector(item).DescendantsChanged -= OnDescendantsChanged;
}
}
To use it, replace instances of ObservableCollection and pass a selector to the collection.
public class FieldInfos
{
private ObservableBubbleCollection<Field> _fields;
public ObservableBubbleCollection<Field> Fields => _fields ?? (_fields = new ObservableBubbleCollection<Field>(fi => fi.Instances));
}
public class Field
{
public string Name;
private ObservableBubbleCollection<FieldInstance> _instances;
public ObservableBubbleCollection<FieldInstance> Instances => _instances ?? (_instances = new ObservableBubbleCollection<FieldInstance>());
}
public class FieldInstance
{
public string Id { get; set; }
}
static class Program
{
static void Main(string[] args)
{
var fi = new FieldInfos();
fi.Fields.DescendantsChanged += (sender, e) =>
{
Console.WriteLine("Change from {0}", sender.GetType());
};
var field = new Field();
fi.Fields.Add(field);
field.Instances.Add(new FieldInstance());
Console.ReadLine();
}
}

Silverlight Datagrid Validation on End Edit

I need to do validation on a grid column. all the cells in that column are blank. the user needs to input data and then i need to validate it.
I have at the moment the validation on the cells working but it works on Begin Edit event instead of the end edit event. which is pointless as the validation needs to check if they have entered information.
How can i get the validation to validate on the end edit Event?
Thank in advance for your help
Niven.
Code:
private string _reference;
public string Reference
{
get
{
return _reference;
}
set
{
_reference = value;
ChangeValue("Reference");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void ChangeValue(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
public string this[string columnName]
{
get
{
string msg = null;
if (columnName == "Reference")
{
if (Reference == "" && ValidateItem)
{
msg = "Reference is Required. Please Enter a Reference";
}
}
return msg;
}
}
string err;
public string Error
{
get { return err; }
}
I've just solved this behavior with the custom code below. I didn't have time to test all scenarios yet, but I'm pretty confident with the results.
public class ExtendedDataGrid : DataGrid {
private ValidationSummary _validationSummary = null;
private bool _validationFilterBehaviorApplied = false;
private bool _validationFilterBehaviorRestored = false;
public ExtendedDataGrid() { }
public override void OnApplyTemplate() {
base.OnApplyTemplate();
this._validationSummary = (ValidationSummary)this.GetTemplateChild("ValidationSummary");
}
protected override void OnBeginningEdit(DataGridBeginningEditEventArgs e) {
if (!_validationFilterBehaviorApplied) {
_validationSummary.Filter = ValidationSummaryFilters.None;
_validationFilterBehaviorApplied = true;
}
base.OnBeginningEdit(e);
}
protected override void OnRowEditEnding(DataGridRowEditEndingEventArgs e) {
if (_validationFilterBehaviorApplied && !_validationFilterBehaviorRestored) {
_validationSummary.Filter = ValidationSummaryFilters.All;
_validationFilterBehaviorRestored = true;
}
base.OnRowEditEnding(e);
}
protected override void OnRowEditEnded(DataGridRowEditEndedEventArgs e) {
_validationFilterBehaviorApplied = false;
_validationFilterBehaviorRestored = false;
base.OnRowEditEnded(e);
}
}

asp.net MVC ActionFilter for remove empty lines in result

Please help me with this action filter.
I think i need to use OnResultExecuted method
How can i have access to otput html and replace something in them?
thank you.
How about using a whitespace removal HTTP module? It's simple to implement, clean and reusable...
http://madskristensen.net/post/A-whitespace-removal-HTTP-module-for-ASPNET-20.aspx
As with any generic whitespace removal solution though, it can easily introduce errors by removing white space where it is required. It wouldn't take long to give it a try though. :-)
Edited after comments
This will not work with .aspx files out of the box so you'll need to change the context_BeginRequest to the following...
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = sender as HttpApplication;
if (app.Response.ContentType == "text/html"
|| app.Response.ContentType == "application/xhtml+xml")
{
app.Response.Filter = new WhitespaceFilter(app.Response.Filter);
}
}
Now I see what you want to do. And I think I might have a solution. I have used parts of this approach in a output cache solution a while back, so I think it will work.
First you need your own stream class that looks like this:
private class CapturingResponseFilter : Stream
{
private readonly Stream _sink;
private readonly MemoryStream _mem;
public CapturingResponseFilter(Stream sink)
{
_sink = sink;
_mem = new MemoryStream();
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { return 0; }
}
public override long Position { get; set; }
public override long Seek(long offset, SeekOrigin direction)
{
return 0;
}
public override void SetLength(long length)
{
_sink.SetLength(length);
}
public override void Close()
{
_sink.Close();
_mem.Close();
}
public override void Flush()
{
_sink.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return _sink.Read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
_mem.Write(buffer, 0, count);
}
public string GetContents(Encoding enc)
{
var buffer = new byte[_mem.Length];
_mem.Position = 0;
_mem.Read(buffer, 0, buffer.Length);
return enc.GetString(buffer, 0, buffer.Length);
}
}
And then you do something like this in your action filter:
private Stream _originalOutputStream;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_originalOutputStream = filterContext.HttpContext.Response.Filter;
filterContext.HttpContext.Response.Flush();
filterContext.HttpContext.Response.Filter = new CapturingResponseFilter(filterContext.HttpContext.Response.Filter);
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (_originalOutputStream == null) return;
filterContext.HttpContext.Response.Flush();
var capturingResponseFilter = (CapturingResponseFilter)filterContext.HttpContext.Response.Filter;
filterContext.HttpContext.Response.Filter = _originalOutputStream;
var textWritten = capturingResponseFilter.GetContents(filterContext.HttpContext.Response.ContentEncoding);
//Do what you want with your text (textWritten).
filterContext.HttpContext.Response.Write(textWritten);
}
I would consider it a little bit of a hack solution. But I haven't seen anything that isn't.
I would like to extend Russel's solution. In MVC or i guess everywhere in beginrequest event the Response.ContentType is "text/html" since we don't know what we will answer.
I founf another event where the content is defined and the filter is applyable: PostReleaseRequestState
https://web.archive.org/web/20211029043851/https://www.4guysfromrolla.com/articles/120308-1.aspx

Resources