In my business logic I have created classes for database operations like insert, update etc.
For this purpose I have created a class CDatabase which sets has some methods define in it like openconnection and closeconnection transation etc.
Now my logic class inherit that class
CAnswerLogic : CDatabase
{
OpenConnection();
BeginTrans();
Command.CommandText = "PKG_ANSWER.PROC_ADD_ANSWERS";
}
Can I get the value of Command.CommandText using reflection. Command is a property inside CDatabse class.
I have written a method to return all the method of a class
private IEnumerable<string> GetAllMethod(string pstrClassName)
{
const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
var llistMethod = new List<string>();
var assembly = Assembly.LoadFile(Server.MapPath(#"bin/InfoDomeBLL.dll"));
try
{
foreach (Type type in assembly.GetTypes())
{
if (type.IsClass && type.Name == pstrClassName)
{
var method = type.GetMethods(flags);
foreach (var methodInfo in method)
{
llistMethod.Add(methodInfo.Name);
//var mb = methodInfo.GetMethodBody();
//foreach (LocalVariableInfo lvi in mb.LocalVariables)
//{
// Response.Write("Local variable: " + lvi);
//}
}
var basetype= type.BaseType;
}
}
}
catch (Exception)
{
}
return llistMethod;
}
In the web project i have added the reference of the bll project.
Kindly help me out.
If you use type.GetProperties(flags); instead of type.GetMethods(flags); you will find the property you are looking for. Then, do propertyInfo.GetValue( Command, null ); to get the value.
Related
I have a piece of code that gets a specific portion of the namespace from the calling assembly. Now I want to unit test this code.
Is there a way to fake the name of the calling namespace using NUnit without implementing the NUnit testcase in that particular namespace?
Here is the method I want to test:
public static string FindCallingNameSpace()
{
var stackTrace = new StackTrace();
var stackFrames = stackTrace.GetFrames();
if (stackFrames != null)
{
int nrFrames = stackFrames.Length;
for (int i = 0; i < nrFrames; i++)
{
var methodBase = stackTrace.GetFrame(i).GetMethod();
var Class = methodBase.ReflectedType;
if (Class != null && Class.Namespace != null && Class.Namespace != "Foo.Common.WebService")
{
var Namespace = Class.Namespace.Split('.');
return Namespace[1];
}
}
}
throw new Exception("Can't determine calling namespace! Need this to determine correct api url to call!");
}
An example would be:
Bar.ExampleNs.SomeMethod() calls Foo.Common.WebService.CallApi() which itself calls the method above to retrieve the namespace from SomeMethod(). The result then would be "ExampleNs".
Now is it possible to create an NUnit UnitTest that is coded in the namespace MyUnitTests.ApiTest.TestNameSpace() but inside Foo.Common.WebService the call appears to come from Bar.ExampleNs.SomeMethod() so I can test for "ExampleNs"?
I think by far the simplest way of achieving what you're after is to just create a call forwarder and call the FindCallingNamespace method via the forwarder. So, assuming that the FindCallingNamespace method is in a class CallerStuff you create this:
namespace SomeNameSpace.ToTest {
static class RemoteCaller {
static public string Run() {
return CallerStuff.FindCallingNameSpace();
}
}
}
Then in your test you call RemoteCaller.Run, rather than CallerStuff.FindCallingNamespace.
However, you mentioned having Parameterized Tests, so presumably you might end up with a few different namespaces you want to test from which would mean more remote callers in different namespaces, which got me thinking that there might be a more generic approach.
The code below, essentially creates these wrapper classes for you by compiling them on the fly and then invoking them.
class CodeMaker {
static string _codesectionOne = #"
using Foo.Common.WebService;
namespace ";
static string _codesectionTwo = #" {
class RemoteCaller {
static public string Run() {
return CallerStuff.FindCallingNameSpace();
}
}
}";
public static string CompileAndCall(string targetNamespace,
string referenceAssembly) {
CompilerParameters CompilerParams = new CompilerParameters();
string outputDirectory = Directory.GetCurrentDirectory();
CompilerParams.GenerateInMemory = true;
CompilerParams.TreatWarningsAsErrors = false;
CompilerParams.GenerateExecutable = false;
CompilerParams.CompilerOptions = "/optimize";
string[] references = { "System.dll", referenceAssembly};
CompilerParams.ReferencedAssemblies.AddRange(references);
CSharpCodeProvider provider = new CSharpCodeProvider();
var codeToCompile = _codesectionOne + targetNamespace + _codesectionTwo;
CompilerResults compile = provider.CompileAssemblyFromSource(CompilerParams,
codeToCompile);
if (compile.Errors.HasErrors) {
string text = "Compile error: ";
foreach (CompilerError ce in compile.Errors) {
text += "rn" + ce.ToString();
}
throw new Exception(text);
}
Module module = compile.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
if (module != null) {
mt = module.GetType(targetNamespace + ".RemoteCaller");
}
if (mt != null) {
methInfo = mt.GetMethod("Run");
}
if (methInfo != null) {
return (string)methInfo.Invoke(null, null);
}
throw new InvalidOperationException("It's all gone wrong!");
}
}
You would then invoke the method from your test:
Assert.AreEqual("Fiddle", CodeMaker.CompileAndCall("Wibble.Fiddle.Con", "SO.dll"));
Assert.AreEqual("Fuddle", CodeMaker.CompileAndCall("Wibble.Fuddle.Con", "SO.dll"));
Note, "SO.dll" in the example above is the name of the assembly containing the CallerStuff.FindCallingNamespace
Using the compiler to generate the caller classes is probably overkill for what you're after and you might have to tweak the error handling in the code if you do decide to use it. If you're invoking the generated classes multiple times from different tests, then it may also be worth caching them, possibly through a dictionary keyed off namespace rather than compiling them every time. Compile + Call code is based on this blog post by Simeon Pilgrim.
How can I run a method that takes parameters from another dll?
I import a UserControl from another dll as below but I now either need to call a method within that UserContol or have the ability to set a variable that's contained in that class.
Load UserControl
UserControl ucSupportButton =
new Bootstrapper().LoadUserControl("SC.Support.dll", "Button");
Code used in Bootstrapper
public UserControl LoadUserControl(string dllName, string loadType)
{
if (File.Exists(Path.Combine(applicationRoot, dllName)))
{
Assembly asm = Assembly.LoadFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), dllName));
Type[] types = asm.GetTypes();
Type type = types.Where(t => t.Name.Equals(loadType)).FirstOrDefault();
if (type != null)
{
return Activator.CreateInstance(type) as UserControl;
}
}
return null;
}
#HighCore comment seems like the best way to go. Depending on your design, reflection is another option. You can use reflection to get a method or field in that type and then call or set it.
var method = paymentObjectInstance.GetType().GetMethod("MethodNameHere",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (method == null)
{
return null;
}
var result = method.Invoke(paymentObjectInstance, null);
Here's a little overview of reflection courtesy of MSDN.
I'm trying to learn reflection in C# and need some help with my code. I've had trouble finding good code examples/guides, so I apologize if my code is poorly done.
Essentially I'm just trying to check out a given assembly dll for a particular method name (path and method name have been redacted).
The problem occurs on the line object lateBoundObj = asm.CreateInstance(typeName); and it reads An object reference is required for the non-static field, method, or property...
I understand this has to do with static vs non-static and creating a new Assembly or something along those lines, but need some help understanding the issue and how to fix it.
Thank you!
public const string assemblyPath = #"<my file path>";
Assembly asm;
static void Main(string[] args)
{
//asm = new Assembly();
Console.Read();
MethodInfo mi;
object result = null;
object[] arguments = new object[] { "ABC123" };
try
{
Assembly assemblyInstance = Assembly.LoadFrom(assemblyPath);
Type[] types = assemblyInstance.GetTypes();
foreach (Type t in types)
{
mi = t.GetMethod("<my method name>");
if (mi != null)
{
string typeName = t.FullName;
object lateBoundObj = asm.CreateInstance(typeName);
result = t.InvokeMember("GetWeb", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, null, lateBoundObj, arguments);
break;
}
}
//set return for find method
}
catch (Exception ex) { }
}
The problem is that you're never assigning a value to asm, so it's got the default value of null. Perhaps you meant to use assemblyInstance instead?
In fact, I wouldn't use Assembly.CreateInstance or Type.FullName at all there - I'd use:
object lateBoundObj = Activator.CreateInstance(t);
Also note, you should always avoid code like this:
catch (Exception ex) { }
Always at least log the exception. Ideally, don't catch an exception you can't really "handle" at all.
asm variable is never assigned. You should call CreateInstance on assemblyInstance instead.
I have a class. I have no influence on thios class, it is coming from somewhere else, from a 3rd party.
I have my own class. When I update it is the same. But it might have missing objects later.
I need to copy Class lets calls it here "source" to my class "target".
source has structs, lists with ints and strings.
First I tried to get down trough it without Reference, it looked like it worked, but the target was empty after that because of the missing reference.
(if anybody wants to see that code let me know).
Now I made a 2nd attempt now: I am not sure if it is the right way, I am having problems copying the values to the right place in the target,
stepping through the class works. Please help me out I need an urgent solution. And please with copying Class existing source to existing target (if the items exisits there in the same struct),
please no suggestions to it totally different because I have no influence on Class source, and Class Target itself, I just need to copy values and subclasses.
Here my code so far. Working through class and subclasses works, have problems setting the values (to the right place):
void refcopyObject(ref object source,ref object target,object svalue,object tvalue)
{
if (source != null && target != null)
{
if (source.GetType() == (typeof(string)))
{
target = source;
}
else
if (source.GetType() == (typeof(int)))
{
target = source;
}
else
if (source.GetType() == (typeof(IntPtr)))
{
target = source;
}
else
{
FieldInfo[] fifsource = source.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); // | BindingFlags.NonPublic
FieldInfo[] fiftarget = target.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); // | BindingFlags.NonPublic
if (fifsource.Length > 0)
{
for (int i = 0; i < fifsource.Length; i++)
{
if (fifsource.GetType() == fiftarget.GetType())
{
if (i < fiftarget.Length)
{
object psource = source.GetType().GetFields();
object ptarget = target.GetType().GetFields();
object vsource = source.GetType().GetFields().GetValue(source);
object vtarget = target.GetType().GetFields().GetValue(target);
refcopyObject(ref psource, ref ptarget, vsource, vtarget);
}
}
}
}
else
{
//Unten angekommen
copySubObject(ref source, ref target, svalue, tvalue);
////So gehts nicht, dann wird die Referenz wieder verloren
//FieldInfo[] fifs = svalue.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); // | BindingFlags.NonPublic
//if (fifs.Length > 0)
//{
// FieldInfo[] fift = tvalue.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); // | BindingFlags.NonPublic
// for (int i = 0; i < fifs.Length; i++)
// {
// if (fifs.GetType() == fift.GetType())
// {
// if (i < fift.Length)
// {
// object psource = svalue.GetType().GetFields().GetValue(svalue);
// object ptarget = tvalue.GetType().GetFields().GetValue(tvalue);
// if (ptarget == null)
// {
// //Ganz unten angekommen, Problem bei Listen
// if (psource.GetType() == (typeof(string)))
// {
// tvalue.GetType().GetFields().SetValue(tvalue,psource);
// }
// if (psource.GetType() == (typeof(int)))
// {
// tvalue.GetType().GetFields().SetValue(tvalue, psource);
// }
// }
// else
// {
// refcopyObject(ref psource, ref ptarget, null, null);
// }
// }
// }
// }
//}
}
}
}
}
I guess the problems start where the comments start. I got to a struct or list at that part, which contain strings or int...
Thanks a lot!
Quick Reply
Well, the simplest way to get a deep copy of a serializable object is to serialize it to a MemoryStream, and then deserialize it back to a new object:
public static T DeepCopy<T>(T other)
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, other);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
}
Note that this requires your source type to be marked with the [Serializable] attribute, and since you don't have access to that code, it doesn't depend on you:
[Serializable]
public class MyClass
{
...
}
Non-serializable classes
There are some solutions which use Reflection to get a deep copy (like CodeProject: Deep copy of objects in C#), although it's important to test if they handle circular references properly. If your object doesn't reference itself (directly or indirectly), you may try this approach.
I have a WCF service that accepts an object as a parameter that has a URI and Method Name.
What I am trying to do is have a method that will look # the URI, if it contains the words "localhost" it will use reflection and call a method, of the name that is passed in as a parameter, within the the same class, return a value and continue on.
public class Test
{
public GetStatResponse GetStat(GetStatRequest request)
{
GetStatResponse returnValue = new GetStatResponse();
if(Helpers.Contains(request.ServiceURI,"localhost", StringComparison.OrdinalIgnoreCase))
{
MethodInfo mi = this.GetType().GetMethod(request.ServiceMethod /*, BindingFlags.Public | BindingFlags.IgnoreCase*/);
returnValue = (GetStatResponse)mi.Invoke(this,null);
}
The above is the code segment pertaining to this question. I pull the MethodInfo no problem but I am running into issues on the mi.Invoke. The exception that I receive is "Exception has been thrown by the target of an invocation." With an Inner Exception "Object reference not set to an instance of an object". I have tried changing the code to (GetStatResponse)mi.Invoke(new Test(), null), with no luck. Test being the class.
I'm open to other suggestions as to how to resolve this, I just thought reflection might be the easiest.
The Method that I am calling with my testing is defined as
public GetStatResponse TestMethod()
{
GetStatResponse returnValue = new GetStatResponse();
Stat stat = new Stat();
Stat.Label = "This is my label";
Stat.ToolTip = "This is my tooltip";
Stat.Value = "this is my value";
returnValue.Stat = stat;
return returnValue;
}
Because you are not specifying BindingFlags in your GetMethod() call, you are only going to be returned methods matching the name containing request.ServiceMethod that are PUBLIC.
Check whether the method you are trying to invoke is public, otherwise MethodInfo will return null.
If it is not public, either make the method public or include the BindingFlags.NonPublic flag.
Also, you should always make sure that mi != null before calling mi.Invoke
Before calling the method you might want to make sure that the MethodInfo you are pulling through reflection is not null:
MethodInfo mi = this.GetType().GetMethod(
request.ServiceMethod,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase
);
// Make sure that the method exists before trying to call it
if (mi != null)
{
returnValue = (GetStatResponse)mi.Invoke(this, null);
}
After your update it seems that the exception is thrown inside the method you are calling:
GetStatResponse returnValue = new GetStatResponse();
// Don't forget to initialize returnValue.Stat before using it:
returnValue.Stat = new WhateverTheTypeIs();
returnValue.Stat.Label = "This is my label";