I have the following, it produces an error saying I need to specify the parameter SearchCriteria which is the only parameter of the stored procedure, am I missing something here?
public async Task<List<T>> SqlQueryAsync<T>(string sql, params object[] parameters) where T : class
{
return await _context.Database.SqlQuery<T>(sql, parameters).ToListAsync();
}
The calling code has this
object[] args = new object[] { searchQuery };
var list = await _repository.SqlQueryAsync<Landlord>(StoredProcedures.LandlordSearch, args);
public static readonly string LandlordSearch = "LandlordSearch #SearchCriteria";
Related
I'm creating a custom result filter that implements IAsyncResultFilter interface. In this filter I need the actual value returned by the Action, but I also need a parameter from that action (This parameter comes from the query string and is used for pagination).
The thing is that I haven't found a way to get the parameter value directly from the ResultExecutingContext that is the variable I have available in the result filter implementation
I've tried to get the parameter value using the context.ActionDescriptor.Parameters, but it's a collection of ParameterDescriptor, and I haven't been able to get the actual value from it, just an instance of ParameterDescriptor
I've been able to get the mediaType from the headers and also the query string itself, but not the query string binded to the PagingModel type.
Is there any way to get this parameter from the ResultExecutingContext variable?
// Action from the ApiController
[HttpGet]
[AddPaginationHeader]
public async Task<IActionResult> Get([FromQuery]PagingModel pagingModel,
[FromHeader(Name = "Accept")]string mediaType) {
var pagedCollection = repository.GetPage(pagingModel);
var shapedCollection = ShapeCollectionOfData(pagedCollection);
return Ok(shapedCollection);
}
// AddPaginationHeader Implementation (Result Filter)
public Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) {
var result = context.Result as ObjectResult;
if (result?.Value != null && result?.StatusCode >= 200 &&
result?.StatusCode < 300) {
// Trying to get the pagingModel (but getting a ParameterDescriptor type)
var pagingModel = context.ActionDescriptor.Parameters.Where(t=>t.Name.Equals("pagingModel")).FirstOrDefault();
//Getting the media type
string mediaType = context.HttpContext.Request.Headers["Accept"]
// Getting the query string itself
string queryString = context.HttpContext.Request.QueryString.ToString();
//Implementation of the actual logic that needs the paging model
// ...
next();
}
return Task.CompletedTask;
}
Based on the answer of Tao I created a nice static method that allows you to get any parameter of any type from a Controller:
private static async Task<TParameter> GetParameterFromAction<TParameter>(ResultExecutingContext context, string parameterName) {
var parameterDescriptor = context.ActionDescriptor.Parameters.Where(t => t.Name.Equals(parameterName)).FirstOrDefault();
ControllerBase controller = context.Controller as ControllerBase;
TParameter parameter = (TParameter)Activator.CreateInstance(parameterDescriptor.ParameterType);
await controller.TryUpdateModelAsync(parameter, parameterDescriptor.ParameterType, string.Empty);
return parameter;
}
For getting PagingModel, you could try TryUpdateModelAsync like
public class AddPaginationHeader : Attribute, IAsyncResultFilter
{
// AddPaginationHeader Implementation (Result Filter)
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
//PagingModel model = new PagingModel();
//await controller.TryUpdateModelAsync(model);
var result = context.Result as ObjectResult;
if (result?.Value != null && result?.StatusCode >= 200 &&
result?.StatusCode < 300)
{
// Trying to get the pagingModel (but getting a ParameterDescriptor type)
var controller = context.Controller as Controller;
var parameterDescriptor = context.ActionDescriptor.Parameters.Where(t => t.Name.Equals("pagingModel")).FirstOrDefault();
var parameter = Activator.CreateInstance(parameterDescriptor.ParameterType);
await controller.TryUpdateModelAsync(parameter, parameterDescriptor.ParameterType, "");
var pagingModel = parameter;
//Getting the media type
string mediaType = context.HttpContext.Request.Headers["Accept"];
// Getting the query string itself
string queryString = context.HttpContext.Request.QueryString.ToString();
//Implementation of the actual logic that needs the paging model
// ...
next();
}
//return Task.CompletedTask;
}
}
In .net core 3.1 you can retrieve parameters and their values in your filter like this:
foreach (var argument in context.ActionArguments)
{
object parameterValue = argument.Value;
string parameterName = argument.Key;
}
This code retrieves parameter values for basic datatypes. You can extend this code to handle objects and lists of values. The argument.Value property will contain the values of the objects properties or list of values.
using the answer from #carlos as a starting point I augmented the implementation a bit to fit my needs. Because Action methods are very unlikely to have multiple parameters with the same type we can use that as the filter instead of parameter name.
public static class ResultExecutingContextExtensions
{
public static async Task<TParameter> GetParameterFromAction<TParameter>(this ResultExecutingContext context) where TParameter : class, new()
{
var parameterDescriptor = context.ActionDescriptor.Parameters
.FirstOrDefault(t => t.ParameterType == typeof(TParameter));
ControllerBase controller = context.Controller as ControllerBase;
TParameter parameter = new TParameter();
await controller.TryUpdateModelAsync(parameter, parameterDescriptor.ParameterType, string.Empty);
return parameter;
}
}
The NancyFx (2.x) NancyModule.Get() method is defined as:
public virtual void Get(string path, Func<dynamic, object> action, [Func<NancyContext, bool> condition = null], [string name = null]);
The normal usage is:
public class MyModule
{
public MyModule()
{
this.Get("/", parameters => {
this.RequestHandler = new RequestHandler();
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
});
}
}
I want to define the second parameter as a property, so that I can use for several paths like this:
public class MyModule
{
Func<dynamic, object> indexHandler = parameters => {
// Error: Keyword "this" is not available in this context
this.RequestHandler = new RequestHandler();
// Error: Keyword "this" is not available in this context
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
};
public MyModule()
{
this.Get("/", indexHandler);
this.Get("/index", indexHandler);
}
}
If I do this it works:
public class MyModule
{
public MyModule()
{
Func<dynamic, object> indexHandler = parameters => {
this.RequestHandler = new RequestHandler();
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
};
this.Get("/", indexHandler);
this.Get("/index", indexHandler);
}
}
But I don't want to define it in the constructor. What am I doing wrong? Is there any other way to do this?
MVCE
Dependancy Package: Nancy (Version: 2.0.0-clinteastwood)
using Nancy;
using Nancy.Responses.Negotiation;
namespace MyNamespace
{
public class MyModule : NancyModule
{
private RequestHandler RequestHandler;
private object IndexHandler(dynamic parameters)
{
this.RequestHandler = new RequestHandler();
var someOtherInfo = "";
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
}
public MyModule()
{
this.Get("/", IndexHandler);
this.Get("/index", IndexHandler);
this.Get("/home", parameters => {
return this.Negotiate.WithView("myview.html");
});
}
}
public class RequestHandler
{
public Negotiator HandleRequest(string path, dynamic parameters, string someOtherInfo)
{
return new Negotiator(new NancyContext());
}
}
}
This should work:
public class MyModule
{
public MyModule()
{
this.Get("/", IndexHandler);
this.Get("/index", IndexHandler);
}
private object IndexHandler(dynamic parameters) {
this.RequestHandler = new RequestHandler();
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
}
}
Andrew's answer is valid and should've been sufficient but apparently (in your MVCE) that method definition doesn't exist.
Here's the correct definition (at least the one VS wants):
public virtual void Get(string path, Func<object, Task<object>> action, Func<NancyContext, bool> condition = null, string name = null)
Luckly your HandleRequest is awaitable so you only need to edit the return type.
Here's the correct definition:
private Task<object> IndexHandler(dynamic parameters)
{
this.RequestHandler = new RequestHandler();
var someOtherInfo = "";
return this.RequestHandler.HandleRequest("/", parameters, someOtherInfo);
}
Hope this helps!
I have a type that has two constructors (ConstructorTestClass), one that has a single parameter of params TestClass[] and the other of TestClass. I have to invoke an instance of TestClass by reflection and then invoke an instance of ConstructorTestClass by reflection using the TestClass instance as the constructor argument.
I want to be able to create my instance of ConstructorTestClass using the params constructor.
Here is a code sample demonstrating my problem;
using System;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var assembly = typeof(ConstructorTestClass).Assembly;
var parameter = assembly.CreateInstance(typeof(TestClass).FullName);
var parameters = new object[] { parameter };
var result = assembly.CreateInstance(typeof(ConstructorTestClass).FullName, false, BindingFlags.CreateInstance, null, parameters, null, null);
Console.WriteLine(result);
Console.ReadLine();
}
}
internal class ConstructorTestClass
{
private readonly string _constructor;
public string ConstructorSignature { get; }
public ConstructorTestClass(params TestClass[] foo)
{
_constructor = "params TestClass[] foo";
}
public ConstructorTestClass(TestClass foo)
{
_constructor = "TestClass foo";
}
public override string ToString() => _constructor;
}
internal class TestClass { }
}
The second constructor (TestClass Foo) is always invoked. If I comment out this constructor the code continues to work but instead calls the other constructor.
I can also get the params constructor to be invoked if I cast the parameters to the correct type;
var parameters = new object[] { new TestClass[] { parameter as TestClass } };
This does not solve the problem however because I would not know the type in the real code in which I need this feature.
I have also tried getting the specific constructor I need and invoking it directly;
var constructor = typeof(DummyConstructorTestClass).GetConstructor(new Type[] { typeof(TestClass[]) });
var result = constructor.Invoke(new object[] { new object[] { parameter } });
Unfortunately this also fails because of the type mismatch (object[] is not TestClass[])
Can I invoke the params constructor by reflection in this case?
With the given information you can create your instance like that:
private static object CallConstructor(Assembly asm, string constructorTestClassName, string testClassName)
{
Type paramType = asm.GetType(testClassName);
var paramsArray = Array.CreateInstance(paramType, 1);
paramsArray.SetValue(Activator.CreateInstance(paramType), 0);
var parameters = new object[] {paramsArray};
return asm.CreateInstance(constructorTestClassName, true,
BindingFlags.CreateInstance, null,
parameters, null, null);
}
I am trying to understand the concept of lambda expression,extension method,Linq and IEnumerable interface. You can guess that i am farely new to c sharp.Here i've come up with a problem which will incorporate all the above mentioned concepts . Here i have a list which contain three object.I want to change the name property of a Students object in a specified index .I wrote an extension method which accept a callback function.Callback function accepts an integer index and a new Name string. It should change the name property and return the object .But my code failed to do so as i am not sure how to pass parameter to Func callback in extension method.I am in need of some assistant to understand the problem and fix errors from my code ?
class Program
{
static void Main(string[] args)
{
List<Students> students = new List<Students>();
students.Add(new Students(111443, "sakib"));
students.Add(new Students(111445, "zami"));
students.Add(new Students(111444, "habib"));
var student = students.First();
var changed1 = students.Change((int num,string newname) => { return students[num].s_name = newname;});
}
}
public class Students
{
public int s_id;
public string s_name;
public Students(int id, string name)
{
this.s_id = id;
this.s_name = name;
}
}
public static class LinqHelper
{
public static IEnumerable<T> Change<T> (this IEnumerable<T> source, Func<int,string,T> callback)
{
var myList = new List<Students>();
myList.Add(callback(1,"zami")); // i was passing parameter here which is not so helpful i guess !
return myList;
}
}
The Func < int, string, T > denotes a function that accepts an integer and string as inputs and T as the return type. The anonymous function you have used has a return type of "string":
var changed1 = students.Change((int num,string newname) => { return students[num].s_name = newname;});
You should return the student instance from the function to make it work. Try replacing the above code with the following:
var changed1 = students.Change((int index, string newname) =>
{
var studentObj = students[index];
studentObj.s_name = newname;
return studentObj;
});
To allow the LinqHelper to accept the index and argument, use the following:
public static class LinqHelper
{
public static IEnumerable<T> Change<T>(this IEnumerable<T> source, Func<int, string, T> callback, int index, string argument)
{
var myList = new List<T>();
myList.Add(callback(index, argument)); // i was passing parameter here which is not so helpful i guess !
return myList;
}
}
And then, you could invoke the method as follows:
var changed1 = students.Change((int index, string newname) =>
{
var studentObj = students[index];
studentObj.s_name = newname;
return studentObj;
},
1,
"zami");
You haven't created the lambda that evaluated to Func<int, string, T>. Your call to Change extension should look like:
var changed1 = students.Change((num, newnam) => {
students[num].s_name = newnam;
return students[num];
});
(you should return T as Func requires).
I am trying to call a method that takes in a function, but using relection. I've gotten it to work when the method is parameterless but I can't figure out how to invoke it when there are arguments. This is a contrived simplified example, but this boils down the problem. I will not know the arguments to Add until runtime.
Any pointers? Do I have to use expression trees? Is there an easier way to do this?
public void Main()
{
//works
CallFunction(typeof (Processor), "Count");
//I don't understand what I need to modify to make add work
CallFunction(typeof (Processor), "Add");
}
public void CallFunction(Type type, string methodToCall)
{
var targetMethod = type.GetMethod(methodToCall);
var constructedType = typeof (MethodCaller<>).MakeGenericType(type);
dynamic target = Activator.CreateInstance(constructedType);
var method = constructedType.GetMethod("Do").MakeGenericMethod(targetMethod.ReturnType);
var func = typeof (Func<,>).MakeGenericType(type, targetMethod.ReturnType);
var toCall = Delegate.CreateDelegate(func, targetMethod);
method.Invoke(target, new object[] { toCall });
}
public class Processor
{
public int Count()
{
return 1;
}
public int Add(int toAdd)
{
return 1 + toAdd;
}
}
public class MethodCaller<TParm> where TParm : new()
{
public TResult Do<TResult>(Func<TParm, TResult> func)
{
return func(new TParm());
}
}
Like type.InvokeMember(method_name, System.Reflection.BindingFlags.InvokeMethod, null, type_instance, new object[] { param1, param2, param3 }); ?
https://msdn.microsoft.com/en-us/library/66btctbe(v=vs.110).aspx
Actually whole CallFunction method can be simplified like this:
public void CallFunction(Type type, string methodToCall, params object[] args)
{
// Why this part is so complex? Do I miss something?
//var constructedType = typeof (MethodCaller<>).MakeGenericType(type);
//dynamic target = Activator.CreateInstance(constructedType);
var target = Activator.CreateInstance(type);
var result = type.InvokeMember(method_name, System.Reflection.BindingFlags.InvokeMethod, null, target, args);
// ... do something with result if you need ...
}
If you need MethodCaller.Do, but can sacrifice types on signature (or some performance on boxing/unboxing for DoTyped)
public void CallFunction(Type type, string methodToCall, params object[] args)
{
var delegate_wrapper = new Func<object, object>(
instance => type.InvokeMember(methodToCall, BindingFlags.InvokeMethod, null, instance, args)
);
var target_method = type.GetMethod(methodToCall);
var mc_custom_type = typeof (MethodCaller<>).MakeGenericType(type);
var mc_instance = Activator.CreateInstance(mc_custom_type);
var mc_custom_method = mc_custom_type.GetMethod("Do").MakeGenericMethod(target_method.ReturnType);
mc_custom_method.Invoke(mc_instance, new object[] { delegate_wrapper });
}
public class MethodCaller<TParm> where TParm : new()
{
public TResult DoTyped<TResult>(Func<TParm, TResult> func)
{
return Do<TResult>(oinstance=>func((TParm)oinstance));
}
public TResult Do<TResult>(Func<object, object> func)
{
Console.WriteLine("I AM DO");
return (TResult)func(new TParm());
}
}
Have you tried looking at Impromptu framework. It is primarily for duck typing but the library provide rather slick api to access methods and pass arguments.
https://github.com/ekonbenefits/impromptu-interface/wiki/UsageReallyLateBinding