I have a problem with casting/types and so on.
Firstly, my query is a follow on from another post here:
Initialize generic object from a System.Type
so to continue on from this question, how can I use the methods of my newly created object?
i.e. what I want to do is as follows:
Type iFace = typeof(IService1);
Type genericListType = typeof(System.ServiceModel.ChannelFactory<>).MakeGenericType(iFace);
object factory = Activator.CreateInstance(genericListType, new object[]
{
new BasicHttpBinding(),
new EndpointAddress("http://localhost:1693/Service.svc")
});
var channel = factory.CreateChannel();
by the way, although I am using this application for WCF, this is not a WCF problem
Try using a dynamic object? This allows you to call methods that might or might not exist.
Without dynamic objects:
object factory = Activator.CreateInstance(genericListType, new object[]
{
new BasicHttpBinding(),
new EndpointAddress("http://localhost:1693/Service.svc")
});
Type factoryType = factory.GetType();
MethodInfo methodInfo = factoryType.GetMethod("CreateChannel");
var channel = methodInfo.Invoke(factory) as YourChannelType;
Related
Hi I am trying to use C# reflection to call a method that is passed a parameter and in return passes back a result. How can I do that? I've tried a couple of things but with no success. I'm used to PHP and Python where this can be done on a single line so this is very confusing to me.
In essence this is how the call would be made without reflection:
response = service.CreateAmbience(request);
request has these objects:
request.UserId = (long)Constants.defaultAmbience["UserId"];
request.Ambience.CountryId = (long[])Constants.defaultAmbience["CountryId"];
request.Ambience.Name.DefaultText = (string)Constants.defaultAmbience["NameDefaultText"];
request.Ambience.Name.LanguageText = GetCultureTextLanguageText((string)Constants.defaultAmbience["NameCulture"], (string)Constants.defaultAmbience["NameText"]);
request.Ambience.Description.DefaultText = (string)Constants.defaultAmbience["DescriptionText"];
request.Ambience.Description.LanguageText = GetCultureTextLanguageText((string)Constants.defaultAmbience["DescriptionCulture"], (string)Constants.defaultAmbience["DescriptionDefaultText"]);
This is my function to implement the reflection where serviceAction for the case above would be "CreateAmbience":
public static R ResponseHelper<T,R>(T request, String serviceAction)
{
ICMSCoreContentService service = new ContentServiceRef.CMSCoreContentServiceClient();
R response = default(R);
response = ???
}
Something along the lines of:
MethodInfo method = service.GetType().GetMethod(serviceAction);
object result = method.Invoke(service, new object[] { request });
return (R) result;
You may well want to add checks at each level though, to make sure the method in question is actually valid, that it has the right parameter types, and that it's got the right return type. This should be enough to get you started though.
Here's a quick example of calling an object method by name using reflection:
Type thisType = <your object>.GetType();
MethodInfo theMethod = thisType.GetMethod(<The Method Name>);
theMethod.Invoke(this, <an object [] of parameters or null>);
If you're on .NET 4, use dynamic:
dynamic dService = service;
var response = dService.CreateAmbience(request);
You can use Delegate.CreateDelegate to obtain a delegate to the method by name:
public static R ResponseHelper<T,R>(T request, string serviceAction)
{
var service = new ContentServiceRef.CMSCoreContentServiceClient();
var func = (Func<T,R>)Delegate.CreateDelegate(typeof(Func<T,R>),
service,
serviceAction);
return func(request);
}
I am trying to load an assembly, System.Speech, via reflection, so that I can use the SpeakAsync method to read aloud some text.
I wrote this:
System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFrom("System.Speech.dll");
System.Type type = assembly.GetType("System.Speech.SpeechSynthesizer");
var methodinfo = type.GetMethod("SpeakAsync", new System.Type[] {typeof(string)} );
if (methodinfo == null) throw new System.Exception("No methodinfo.");
object[] speechparameters = new object[1];
speechparameters[0] = GetVerbatim(text); // returns something like "+100"
var o = System.Activator.CreateInstance(type);
methodinfo.Invoke(o, speechparameters);
But get the error
System.NullReferenceException: Object reference not set to an instance of an object
Your code contains bug, you can't work with class if you specified incorrect namespace (neither via reflection nor without it)
You use incorrect namespace here (that's why you received null reference exception ):
System.Type type = assembly.GetType("System.Speech.SpeechSynthesizer");//type == null
Here is example of correct namespaces:
System.Type type = assembly.GetType("System.Speech.Synthesis.SpeechSynthesizer");
Update1:
Another note. invoke returns a prompt, and you shouldn't exit the programm while asynchronous method is working (off course, only if you really want to listen speech to the end). I added few lines to your code to wait until speach will be finished:
internal class Program
{
private static void Main(string[] args)
{
var assembly = Assembly.LoadFrom("System.Speech.dll");
var type = assembly.GetType("System.Speech.Synthesis.SpeechSynthesizer");
var methodinfo = type.GetMethod("SpeakAsync", new[] {typeof(string)});
if (methodinfo == null) throw new Exception("No methodinfo.");
var speechparameters = new object[1];
speechparameters[0] = "+100"; // returns something like "+100"
var o = Activator.CreateInstance(type);
var prompt = (Prompt) methodinfo.Invoke(o, speechparameters);
while (!prompt.IsCompleted)
{
Task.Delay(500).Wait();
}
}
}
Update 2
Make sure you have the correct language pack.
MSDN
Update 3
If you use Mono, try to make sure that this feature should works on Mono. I gues there are some problems with Mono realization.
I'm trying to test a custom model binder. As part of that process I am creating a new ModelBindingContext to pass into the BindModel method of the custom binder. The problem is that I need to set the MetaData property of the ModelBindingContext as a CachedDataAnnotationsModelMetadata object, but honestly am not sure how to instantiate the object.
The signature for the CachedDataAnnotationsModelMetadata object is:
public CachedDataAnnotationsModelMetadata(
CachedDataAnnotationsModelMetadata prototype,
Func<object> modelAccessor
)
Does anyone have an example of what the prototype and modelAccessor parameters are supposed to be?
Here's a snippet of the non-functional code.
// Assemble
var formCollection = new List<KeyValuePair<string, string>> {
new KeyValuePair<string, string> ("SomeRequiredProperty", "SomeValue")
};
var valueProvider = new System.Web.Http.ValueProviders.Providers.NameValuePairsValueProvider(formCollection, null);
var metadata = new System.Web.Http.Metadata.Providers.CachedDataAnnotationsModelMetadata(????, ????)
var bindingContext = new ModelBindingContext {
ModelName = "ClaimsModelBinderInputModel",
ValueProvider = valueProvider,
ModelMetadata = metadata
};
var actionContext = new HttpActionContext();
var httpControllerContext = new HttpControllerContext();
httpControllerContext.Request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/someUri");
actionContext.ControllerContext = httpControllerContext;
var cmb = new ClaimsModelBinder();
// Act
cmb.BindModel(actionContext, bindingContext);
// Assert...
I've found a few examples around the net and SO of people interacting with this class, but no concrete example of implementing it.
Thanks in advance!
Update
Figured out ModelAccessor, it's just used to delay accessing the actual model until the model property is accessed. https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Http/Metadata/ModelMetadata.cs#L103
I'm still working on supplying a prototype object if anyone can help with that.
So I ended up sidestepping this issue entirely.
After inspecting the inheritance model, I realized that in this case I can get away with using the DataAnnotationsModelMetadataProvider rather than the CachedDataAnnotationsModelMetadata. The latter of these doesn't require the parameters necessary to setup caching, and since I don't need caching to test what I am testing, the standard DataAnnotationsModelMetadataProvider will suffice.
I was able to identify that I could take a different approach after reading through the source code for the metadata namespace.
https://github.com/ASP-NET-MVC/aspnetwebstack/tree/master/src/System.Web.Http/Metadata
That said, if anyone else can provide some clues to my original question, I would prefer to use the cached model object if possible.
I'm coming from Web Api so maybe this question will be a little weird.
I'm working in Visual Studio 2012
Scenario:
I've two WCF services right now (but in the future will be more) that accept the same object (suppose datacontract A with same datamembers)
I'm calling them in this way:
string url1 = "myURL1";
BasicHttpBinding binding1 = new BasicHttpBinding();
EndpointAddress address1 = new EndpointAddress(url1);
ServiceClient1 serviceClient1 = new ServiceClient1(binding1, address1);
string url2 = "myURL2";
BasicHttpBinding binding2 = new BasicHttpBinding();
EndpointAddress address2 = new EndpointAddress(url2);
ServiceClient2 serviceClient2 = new ServiceClient2(binding2, address2);
Question:
It is possible call them dinamically? In one only method in order to just change the urls?
Update
Is it possible call them without any reference of the type? Because I need use a common method in both and that method receives the same object and retrieves the same object.
T CreateServiceClient<T>(string url)
{
var binding = new BasicHttpBinding();
var endpointAddress = new EndpointAddress(url);
return (T) Activator.CreateInstance(typeof(T), new object[] {binding, endpointAddress});
}
Should be able to use it like so:
var client1 = new CreateServiceClient<ServiceClient1>("http://...");
var client2 = new CreateServiceClient<ServiceClient2>("http://...");
You can look into generics and try to constrain T to be more specific as this doesn't give you any type safety.
If you mean dynamically like you only have a Type, you can do this:
object CreateServiceClient(Type serviceClientType, string url)
{
var binding = new BasicHttpBinding();
var endpointAddress = new EndpointAddress(url);
return Activator.CreateInstance(serviceClientType, new object[] {binding, endpointAddress});
}
Just change object to be a more generic interface or class that all of your clients adhere to if you have one defined.
EDIT
Based on your updated question you will need to do one of two things
Implement an interface or a base class for your common services with the common methods you are needing to invoke. The above code will still work, just need to cast your new common type.
Use reflection to dynamically invoke the common method you are needing. This won't give you any compile time checks or errors and any issues will only be found during runtime.
I highly recommend #1, but if for some reason that is not possible, you can do #2. If you need to do #2, you could meet halfway between the two and implement a wrapper class that tries to union some of this functionality:
public class MyServiceWrapper
{
Type _serviceType;
public MyServiceWrapper(Type serviceType)
{
_serviceType = serviceType;
}
public object CreateInstance()
{
... code from above ...
}
public YourObject InvokeServiceMethod()
{
var instance = CreateInstance();
var methodInfo = _serviceType.GetMethod("MethodName");
return (YourObject) methodInfo.Invoke(instance, anyArguments);
}
}
given the following classes:
class SomeBuilder<T>
{
public static object Build(int index)
{
...
}
}
class SomeHelper
{
public object GetBuildObj(object value)
{
var valuetype = value.GetType();
var methodinfo = typeof(SomeBuilder<>).MakeGenericType(valuetype).GetMethod("Build");
var handler = SomeDynamicHelper.GetMethodInvoker(methodinfo);
var result = hander(null, new object[]{1});
}
}
SomeBuilder was a generic type so i need a call to MakeGenericType() to make things right.
when i pass a normal type like 'class person' for the value, everything just works, that`s fine.
but when i pass a anonymous type like: new { id=1 }, the handler was successfully created. but invoke this dynamic handler i got a MethodAccessException with these messages:
"method "SomeDynamicHelper.(System.Object, System.Objec[])" try to access method "SomeBuilder'1<<>f__AnonymousType0'1<System.Int32>>.Build(int)" failed.
any help would be appreciated, thx.
btw, if you are interested in SomeDynamicHelper, plz see:
http://www.codeproject.com/Articles/14593/A-General-Fast-Method-Invoker
edit1:
i did the call in main like this:
static void Main(string[] args)
{
// pass a normal class, this will be fine
var value = new Person { id = 1};
new SomeHelper().GetBuildObj(value);
// pass a anonymous type
var value = new { id = 1};
new SomeHelper().GetBuildObj(value); // oops, got a exception here!
}
edit2:
based on the comment i changed my code:
class SomeHelper
{
public object GetBuildObj(object value)
{
//this time i do not use the value, but create a new inner value:
var valuenew = new { id = 1 };
var valuetype = valuenew.GetType();
var methodinfo = typeof(SomeBuilder<>).MakeGenericType(valuetype).GetMethod("Build");
var handler = SomeDynamicHelper.GetMethodInvoker(methodinfo);
var result = hander(null, new object[]{1});
}
}
well, this time there is no exception, but...unfortunately a new problem occured...may be i should open a new thread for the new problem.
thank you guys, for your attentions.
edit3:
hi, after some digging, i also found some useful information. say, the SomeDynamicHelper.GetMethodInvoker() code as below:
DynamicMethod dynamicMethod = new DynamicMethod(string.Empty, typeof(object), new Type[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module);
this is the core we used here to dynamic create a method. for our context, we need to declare the anonymous type in same assembly with the SomeHelper and SomeBuilder. but, if we can`t do the declaration, what should we do?
ok, you can call DynamicMethod() with last parameter(the skipVisibility), set to true!
hope this will help others with the same problem :)
"method "SomeDynamicHelper.(System.Object, System.Objec[])" try to access method "SomeBuilder'1<<>f__AnonymousType0'1>.Build(int)"
From this you can see that dynamic method try to run an internal\private method called Build, for that you got MethodAccessException.
(The anonymous type is kept in a new generated class)
Adding InternalVisibleTo not always helping because it's helping only if you can rewrite the anonymous type assembly (manually or with interception) and only if the type and method are internals and not private.
In dynamic method you can bind the method to type\module, and to skip visibility check, but this help to access private members of the specified module, so again if the type you trying to access is in a different assembly and the type\method are private you can't do anything.
Well almost. There is a "secret" attribute that you inject to your assembly, called IgnoreAccessChecksTo and then in addition to bounded module and skip visibility maybe it will work.
You can try using [assembly: InternalsVisibleTo("Anonymously Hosted DynamicMethods Assembly")] in the same project where you define the anonymous type.
I had a similar error with a C# class I tried to inject using IKVM-converted Guice. The fix was simply making the affected class (in this case probably SomeBuilder) public and everything worked fine.