I'd like to assign a function to the OnTicketReceived property of the OAuthEvents object (https://learn.microsoft.com/en-us/aspnet/core/api/microsoft.aspnetcore.authentication.oauth.oauthevents)
It is a Func<TicketReceivedContext, Task>
public class MyClass
{
public void Config()
{
var o = new OAuthEvents
{
OnTicketReceived = MyFunc; //Doesn't work
};
}
public Task MyFunc(TicketReceivedContext ctx)
{
return Task.CompletedTask;
}
}
I know I can write an anonymous method using a lambda but I don't want to do that because I wish to reuse the method in multiple places. How is this supposed to be done?
Related
I'm sorry to ask, how can i invoke method using other that method.Invoke, because some article said, method.Invoke has slower performance.
Actually i'm using .NET Core 3.1.
Example, i have a structure code something like this.
public class Message { }
public class MyMessageType : Message { }
public class MyMessageResult
{
public bool Status { get; set; }
public DateTime Date => DateTime.Now;
}
public interface IEncapsulatedMessageHandlerV2<T, TResult> where T : class
{
Task<TResult> HandleMessageResultAsync(T message);
}
public abstract class EncasulatedMessageHandlerV2<T, TResult> : IEncapsulatedMessageHandlerV2<T, TResult> where T : Message
{
public abstract Task<TResult> HandleMessageResultExecAsync(T message);
async Task<TResult> IEncapsulatedMessageHandlerV2<T, TResult>.HandleMessageResultAsync(T message)
{
var msg = message as T;
if (msg != null)
return await HandleMessageResultExecAsync(msg);
return default;
}
}
public class HandlerV2 : EncasulatedMessageHandlerV2<MyMessageType, MyMessageResult>
{
public override Task<MyMessageResult> HandleMessageResultExecAsync(MyMessageType message)
{
Console.WriteLine("Yo Async!");
return Task.FromResult(new MyMessageResult
{
Status = true
});
}
}
And i can successfully call using method.Invoke
static TResponse UsingMethodInvoke<TResponse>()
{
// Assume, i was build this using MakeGenericMethod
var type = typeof(IEncapsulatedMessageHandlerV2<MyMessageType, MyMessageResult>);
var typeActivator = typeof(HandlerV2);
var instance = Activator.CreateInstance(typeActivator);
var method = type.GetMethod("HandleMessageResultAsync");
var tsk = (Task<TResponse>)method.Invoke(instance, new[] { new MyMessageType() });
var result = tsk.GetAwaiter().GetResult();
return result;
}
And i try to using Dynamic too, unfortunately they can't calling through abstract HandleMessageResultAsync instead only through implemented class HandleMessageResultExecAsync
static TResponse UsingDynamicInvoke<TResponse>()
{
// Assume, i was build this using MakeGenericMethod
var typeActivator = typeof(HandlerV2);
var instance = Activator.CreateInstance(typeActivator);
var tsk = (Task<TResponse>)((dynamic)instance).HandleMessageResultExecAsync(new MyMessageType());
var result = tsk.GetAwaiter().GetResult();
return result;
}
And i was follow to with stackoverflow Speeding up Reflection Invoke C#/.NET, and i get stuck
static void ActivatorMyMessageResultAsnc()
{
var type = typeof(HandlerV2);
var instance = Activator.CreateInstance(type);
var method = type.GetMethod("HandleMessageResultAsync", BindingFlags.Instance | BindingFlags.Public);
var originalType = type;
// Loop until we hit the type we want.
while (!(type.IsGenericType) || type.GetGenericTypeDefinition() != typeof(EncasulatedMessageHandlerV2<,>))
{
type = type.BaseType;
if (type == null)
throw new ArgumentOutOfRangeException("type");
}
var messageType = type.GetGenericArguments()[0]; // MyMessageType
// Use expression to create a method we can.
var instExpr = Expression.Parameter(typeof(object), "instance");
var paramExpr = Expression.Parameter(typeof(Message), "message");
// (Handler)instance;
var instCastExpr = Expression.Convert(instExpr, originalType);
// (MyMessageType)message
var castExpr = Expression.Convert(paramExpr, messageType);
// ((Handler)inst).HandleMessage((MyMessageType)message)
var invokeExpr = Expression.Call(instCastExpr, method, castExpr); // <--- this give me error
// i'm stuck, i don't know what should i do next
////// Assume this is build from MakeGeneric too
////var delType = typeof(Func<object, Message, Task<MessageResult>>);
//var lambda = Expression.Lambda<Func<object, Message, Task<object>>>(invokeExpr, instExpr, paramExpr);
//var compiled = lambda.Compile();
//Func<Message, Task<object>> hook = x => compiled(instance, x);
Or, is there any other ways to Invoke method by dynamicaly, which is faster that method.Invoke
Thanks in advance,
PS: Sorry for my Bad English
I had a similar problem I was trying to solve a while back. I dug into the Net Core codebase and found a class which is really helpful for invoking methods at runtime without being strongly typed.
https://github.com/dotnet/extensions/blob/ff87989d893b000aac1bfef0157c92be1f04f714/shared/Microsoft.Extensions.ObjectMethodExecutor.Sources/ObjectMethodExecutor.cs
ObjectMethodExecutor lets you call a method on an object using its name. An example of usage is:
var methodInfo = [myInterface].GetMethod("[method-you-want-call]");
var classTypeInfo = [myClass].GetTypeInfo();
var executor = ObjectMethodExecutor.Create(methodInfo, classTypeInfo);
await executor.ExecuteAsync(handler, new[] { [data-you-want-to-pass-to-your-object] });
Its used extensively in the SignalR codebase for matching SignalR messages to the internal methods on a hub. Its heavily optimised and has the added benefit of allowing async methods to be called too
I would like to create a proxy class that will be able to retrieve the name of a method given in argument, and an instance of a paramater with generic completion (aka I don't want nameof() or magic strings).
For example, I would like to be able to do something like
public interface ITestInterface
{
void TestMethod(Param myParam)
}
var proxy = new Proxy<ITestInterface>();
var param = new Param();
proxy.WriteName(x => ITestInterface.TestMethod(param));
and the proxy class be able to retrive the name of the method and do a tostring on the instance of the parameter :
public class Proxy<T>
{
public void WriteName(Something something)
{
Console.WriteLine(something.MethodName); // write "TestMethod"
Console.WriteLine(something.Parameter.ToString()); // use the tostring of the instance object
}
}
Thanks for your help
I would say it would not be easy to support all possible scenarios but for what you have described in the question you can try using expression trees:
public class Proxy<T>
{
public void WriteName(Expression<Action<T>> something)
{
// TODO: add correct handling for not supported operations
if (something.Body is MethodCallExpression mc)
{
Console.WriteLine(mc.Method.Name);
foreach (var arg in mc.Arguments)
{
if (arg is MemberExpression me && me.Expression is ConstantExpression cnst)
{
var val = me.Member.MemberType switch
{
MemberTypes.Field => ((FieldInfo)me.Member).GetValue(cnst.Value),
MemberTypes.Property => ((PropertyInfo)me.Member).GetValue(cnst.Value),
_ => null
};
Console.WriteLine(val);
}
}
}
}
}
And usage:
var proxy = new Proxy<ITestInterface>();
var param = new Param();
proxy.WriteName(t => t.TestMethod(param)); // actually many more can be passed here
If I understand correctly you can try this:
public class Proxy<T>
{
public void WriteName(Expression<Action> action)
{
var methodCallExp = (MethodCallExpression)action.Body;
Console.WriteLine(methodCallExp.Arguments.First().ToString());
Console.WriteLine(methodCallExp.Method.Name);
}
}
and call proxy class like this:
var proxy = new Proxy<ITestInterface>();
proxy.WriteName(() => new ConcreteTestInterface().TestMethod(param));
I try to test the result of some function where a call to an extension method is used. This extension method is defined on an interface. The test setup creates a mock of said interface. For this mock two setups are configured. When calling these setup function on the mocked interface implementation, everything works as intended. (see TestMockSetupSourceClassA and TestMockSetupSourceClassB) But when these calls are made in the extension method the result is null. (see TestDoClassStuff)
I've set up a test project: https://github.com/sschauss/MoqExtensionMethodTest
Extension
public static class ExtensionClass
{
public static TResult DoExtensionStuff<TResult>(this ISomeInterface someInterface, object initialObject,
params object[] objects)
{
var result = someInterface.DoInterfaceStuff<TResult>(initialObject);
return objects.Aggregate(result, (agg, cur) => someInterface.DoInterfaceStuff(cur, agg));
}
}
Implementation
public class SomeClass
{
private readonly ISomeInterface _someInterface;
public SomeClass(ISomeInterface someInterface)
{
_someInterface = someInterface;
}
public TargetClass DoClassStuff(SourceClassA sourceClassA, SourceClassB sourceClassB)
{
return _someInterface.DoExtensionStuff<TargetClass>(sourceClassA, sourceClassB);
}
}
Test
public class UnitTest
{
private readonly SomeClass _sut;
private readonly SourceClassA _sourceA;
private readonly SourceClassB _sourceB;
private readonly TargetClass _target;
private readonly Mock<ISomeInterface> _someInterfaceMock;
public UnitTest()
{
_sourceA = new SourceClassA
{
Integer = 1
};
_sourceB = new SourceClassB
{
String = "stringB"
};
_target = new TargetClass
{
Integer = 2,
String = "stringT"
};
_someInterfaceMock = new Mock<ISomeInterface>();
_someInterfaceMock.Setup(m => m.DoInterfaceStuff<TargetClass>(_sourceA)).Returns(_target);
_someInterfaceMock.Setup(m => m.DoInterfaceStuff(_sourceB, _target)).Returns(_target);
_sut = new SomeClass(_someInterfaceMock.Object);
}
[Fact]
public void TestDoClassStuff()
{
var result = _sut.DoClassStuff(_sourceA, _sourceB);
result.Should().BeEquivalentTo(_target);
}
[Fact]
public void TestMockSetupSourceClassA()
{
var result = _someInterfaceMock.Object.DoInterfaceStuff<TargetClass>(_sourceA);
result.Should().BeEquivalentTo(_target);
}
[Fact]
public void TestMockSetupSourceClassB()
{
var result = _someInterfaceMock.Object.DoInterfaceStuff(_sourceB, _target);
result.Should().BeEquivalentTo(_target);
}
}
The problem has to do with the Aggregate extension, its generic argument parameters and what you have Setup the mock to expect.
The params of the extension method DoExtensionStuff is an object array so when calling the `
T2 DoInterfaceStuff<T1, T2>(T1 parameter1, T2 parameter2)
within the Aggregate delegate you are actually passing
(TResult agg, object cur) => someInterface.DoInterfaceStuff<object,TResult>(cur, agg)
which the mock was not configured to handle.
After changing the _someInterfaceMock.Setup, in this particular case, explicitly to
_someInterfaceMock
.Setup(m => m.DoInterfaceStuff<object, TargetClass>(_sourceB, _target))
.Returns(_target);
All the tests in this scenario were able to be exercised to completion successfully.
The thing with Moq is that when a mock is not told explicitly what to expect it will return null by default for reference types.
How can I make the Predicate return a bool value from async method C#
private void OnFilterTextBoxTextChangedHandler(object oSender, TextChangedEventArgs oArgs)
{
//Other operations
_oCollectionView.Filter = new Predicate<object>(DoFilter); //wrong return type
}
Returning method
private async Task<bool> DoFilter(object oObject)
{
if (_sFilterText == "")
{
return true;
}
return false;
}
Predicate<T> is a delegate. You don't need to instantiate a new predicate when adding a filter to your CollectionView. Instead, you can add your filter like this:
_oCollectionView.Filter = DoFilter;
Second, the signature of the CollectionView.Filter delegate is public delegate bool Predicate<object>(object obj). The parameter obj is the element of the CollectionView that is being evaluated. You cannot alter this signature to make it asynchronous.
In your example, I would look at doing the following:
constructor()
{
InitializeComponent();
// Alternatively put this in an initialization method.
_oCollectionView.Filter = DoFilter;
}
private async void OnFilterTextBoxTextChangedHandler(object oSender, TextChangedEventArgs oArgs)
{
// Other operations
// Asynchronous processing
await SetupFilterAsync();
_oCollectionView.Refresh();
}
private async Task SetupFilterAsync()
{
// Do whatever you need to do async.
}
private bool DoFilter(object obj)
{
// Cast object to the type your CollectionView is holding
var myObj = (MyType) obj;
// Determine whether that element should be filtered
return myObj.ShouldBeFiltered;
}
You can also define your filter as a lambda, which would look like this and eliminate the DoFilter method:
_oCollectionView.Filter = x => ((MyType)x).ShouldBeFiltered;
I have the following code:
private void StartTask<T>(string parameter)
{
dynamic instance = (T) Activator.CreateInstance(typeof(T), parameter);
Task.Factory.StartNew(() => instance.DoCompare());
}
This does not work and the "DoCompare()" method does not get called...How do I call a method in a class with parameters in a generic type method?
Class I am initiating:
public class Something {
private string _parameter;
public Something(string parameter) {
_parameter = parameter;
}
public void DoCompare(){
//Do longrunning task
}
}
EDIT: Removed constraint BaseClass5 because of confusion
EDIT2: I get: A first chance exception of type
'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'
EDIT3:
This seems to work, the issue seems to be Task.Factory.StartNew:
private void StartTaskAwesomium<T>() where T
{
dynamic instance = (T) Activator.CreateInstance(typeof (T), parameter);
instance.Test();
}
In theory your code should work, but it is a "fire-and-forget" pattern, meaning it will be executed sometime, but you have no control over that or can check if it actually was executed or if there was an exception.
Maybe change it to:
private async void StartTask<T>(string parameter) where T : BaseClass5
{
BaseClass5 instance = (T)Activator.CreateInstance(typeof(T), parameter);
await Task.Factory.StartNew(() => instance.DoCompare());
}
No need for the dynamic as because of your generic constraint you know that T must be BaseClass5 or based on it.
Or return the task to await (or task.Wait()) it elsewhere:
private Task StartTask<T>(string parameter)
{
T instance = (T)Activator.CreateInstance(typeof(T), parameter);
return Task.Factory.StartNew(() => instance.DoCompare());
}
The solution was to wrap the creation of the class in the Task itself like this:
private void StartTask<T>(string connectionId) where T : BaseClass5
{
Task.Factory.StartNew(() =>
{
dynamic instance = (T) Activator.CreateInstance(typeof (T), connectionId);
instance.DoCompare();
});
}
private void StartTask<T>(string parameter)
{
dynamic instance = (T) Activator.CreateInstance(typeof(T), parameter);
Task.Factory.StartNew(() => {instance.DoCompare();});
}
This seems to work.