Get Calling Method information

Published 3/31/2008 by Dave in dotNet
Tags:

The following i would use in Logging code. Its a simple Idea, you log the error with and add what function went wrong.

Here is the function:

/// <summary>
/// Gets the Actal calling function.
/// B -> C(string) -> C()
/// will return B as C(String) is the
/// overloaded function. and not required
/// </summary>
/// <returns>Returns the Calling function, not the overloaded one.</returns>
public static StackFrame GetCallingMethod()
{
    string current = new StackFrame(1, false).GetMethod().Name;
    int FrameNumber = 1;
    StackTrace st = new StackTrace(true);
    StackFrame sf;
    while (FrameNumber < st.FrameCount) {
        FrameNumber += 1;
        sf = st.GetFrame(FrameNumber);
        if (!current.Equals(sf.GetMethod().Name)) {
            return sf;
        }
    }
    return null;
}

Now you may say, will i can get the calling method in one line of code!. well sure you can, but this is a bit more than that. It considers overloaded methods.

For example:

A simple logging function, where the coder has 2 overloads to choose from.

/// <summary>
/// norammly will log out to a Database
/// </summary>
/// <param name="ex">exception to log</param>
/// <param name="rethrow">indecate if the log should re
/// throw the execption</param>
static void LoggingFunction(Exception ex, bool rethrow)
{
    StackFrame stackFrame = GetCallingMethod();
    string callingFunction = stackFrame.GetMethod().Name;

    string log =
        string.Format(
        "Function: {0} failed, with the following message\n{1}",
        callingFunction, ex.Message);
    Console.WriteLine(log);

    if(rethrow)
        throw ex;
}


/// <summary>
/// this will silently log an error, the
/// exception will not be rethrown
/// </summary>
/// <param name="ex">the exception to log</param>
static void LoggingFunction(Exception ex)
{
    LoggingFunction(ex, false);
}

The second logging functions calls the first, passing in the rethow param. Also note that the first function is the only one which has the GetCallingMethod() call.

finally here is a fuction which uses the logging in case it fails (Ok this will fail every time, but use your imagination)

/// <summary>
/// the main overload
/// </summary>
/// <param name="name"></param>
static void WriteHelloWorld(string name)
{
    try
    {
        //this would normally work
        //but for this test i will throw an error:
        Console.WriteLine("Hello :" + name);
        throw new SystemException("something when wrong!");
    }
    catch(Exception ex)
    {
        LoggingFunction(ex);
    }
}

When this WriteHelloWorld function is called, it fails calling the second logging function, which calls the first logging function. And this then logs out to the screen, giving the correct name of the function which failed, and called the logging functions.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Quick info

Very quick guide, ORM stands for Object Relational Mapper, its a tool which takes the data from a database and populates this data into Business Objects.. Nice and simple... basically using an ORM should save you as a coder from having to write the Data Access Layer code. (I'm not saying this is the best way to do things, that boils down to what you need to do.) For this code example i will be using WilsonORM there is a free download which will allow you to create a debug only project (other than that you have to pay a one off charge).

Back to the sample code.

1.Table

Lets start with the database, I will use one that came with this blog (a little change from northwind, I may do it with step 2).

CategoryId = GUID
CategoryName = Varchar(50)

I will only concentrate on this single table (keep it simple)

2. .Net Code

Now we will have to create a console application which will be extremely simple, it will contain the business object class for the above table, and a simple script which will list all the Categories in this table.

  1. Create a new console project all this "TestOfORM"
  2. Add a reference to the WilsonORMapper.dll (I'm using the .net 2 version, but the 1.1 will do)
  3. Now add a BO sub folder in your project.

Now lets review what is required to get this to work:

  • Corresponding Business Object Class
  • Manager Class, basically is use to initiate the Object Space
  • Mapping File (contains meta data of how the table relates to the Business Object Class)
  • Actual Application code.

3. The Business Object Class

This class will be used to store the information for an instance of data in the table. Here is what my Class will look like

Things to note, you need a parameterless constructor, also there is s field which will relate to the columns in the table.

4. Manager Class

This will create an instance of the ORM manger (object Space), this will be used in your app code to load data from the database.

using System;
using Wilson.ORMapper;

namespace TestOfORM
{
    sealed public class Manager
 {
  private static ObjectSpace engine;

  public static ObjectSpace Engine {
   get { return Manager.engine; }
  }

  static Manager() {
   string mappingFile = AppDomain.CurrentDomain.BaseDirectory
                + "Mappings.xml";
   string connectString = @"Server=.\sqlexpress;DataBase=theBlogDB;UID=user;PWD=passsword;";
   string providerType = "MsSql";

   Provider provider;
   try { provider = (Provider) System.Enum.Parse(typeof(Provider), providerType, true); }
   catch { provider = Provider.MsSql; }

   // Note: Non-Zero Session may be desirable for Server Applications
   engine = new ObjectSpace(mappingFile, connectString, provider);
  }

  private Manager() {
   // Note: Static Class -- All Members are Static
  }
 }
}

this code i just copied off Wilson's site, and changed the mappingFile and connectionString varibles.. now you are almost there.

5. Mapping file

This file will contain all the entity mappings, the easiest way to build this file is to copy one off a sample which comes with the OEM and change it to your requirements. One cool thing is Paul Wilson included the .XSD file, so you can set this to validate your shema.

<?xml version="1.0" encoding="utf-8" ?>
<mappings version="4.2">
  <entity type ="TestOfORM.BO.be_Categories" table ="be_Categories" keyMember ="_CategoryID" keyType="Auto">
    <attribute  field ="CategoryID" member ="_CategoryID" alias ="CategoryID" />
    <attribute field ="CategoryName" member ="_CategoryName" alias ="CategoryName"/>
  </entity>
</mappings>

as you can see there is only 1 entity, with 2 attributes.. this is mapping the be_Categories table to the  be_Categories class, things to notes:

  • keyType - is how the Primary key is generated
  • KeyMember - is the tables primary key

6. Your App Code

finally you can code your app, it may seem like a lot of work, but the larger the project the more likely you would find this faster to code, plus some of the you can generate using tools

class Program
{
    static void Main(string[] args)
    {
        ObjectSet allCat = Manager.Engine.GetObjectSet(typeof (be_Categories), string.Empty);
       
        foreach (object o in allCat)
        {
            be_Categories cat = (be_Categories) o;
            Console.WriteLine(cat.CategoryName );
        }
        Console.ReadLine();
    }
}

as you can see I call the managers get all of that type, which returns an ObjectSet, then i just list all the entries. Nice and simple. The following screen shot shows the final layout of my project:

and here is the result for my test DB

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Well using this awesome blog, i noticed that it can easily handle extension from other coders. Well this lead me to thinking of building a Windows/Console Proof of Concept (PoC) project. The goal was to see how to engineer a program which can use plug-ins (developed by others) and instantly use them without the need to recompile the code. Thus a truly pluggable program. Well here is the good news, its easier than I had thought to do it with .Net, so lets start.

My PoC is split into 3 projects

  1. interfaceLib (class lib) - this stores all the public interfaces supported by the application.
  2. Plugin (Class lib) - a very simple plug in (Hello world, what else)
  3. PlugControlApp (Win app) - this is the main application, which will be able to load in the Plug in and use it.

Why do i have the interface as a different project?.
1. allows you to only share the interface code
2. allows developers to save/reference only the interfaceLib project, and be able to build and compile their plug-in
3. keeps things a little simpler (well it did in this example.)

1. interfaceLib  (Design by Interface)

If you have used Design Patterns or the Enterprise Library, you may note the increase in Design by interface (hopefully you are very used to this idea). if your note i really would recommend googling this (I may write an example app at a later date to demo this concept). ANYWAY going off track....

In my example I want to be able to

  • Find what version of my application the plug is written for
  • Find the Name of the plug in
  • Have a DoSomthing function which takes in a string and returns a string.

Here is the class Diagram:

I decided to split them into 2 different interfaces as the Plugin interface would be useful for all my plug-ins, and the DoSomthing interface seemed more specialized.

2. Plugin - The outside world can help! YEAH!

This project can reference the interfaceLib, allowing the developer to build and compile a plug in control, with out the need to reference the actual application. For the plug in all i really wanted to do is to have a Hello world.... so to accomplish this the plug-in will need to follow these steps

  • Remember to add a reference to the interfaceLib and using statement

using interfaceLib;

  • In your class inherit off the required interfaces (DoSomthing in this case)

/// <summary>
/// Simple hello world plug-in!
/// </summary>
public class WriteHello : DoSomething
{

  • implement the methods to satisfy the contract of the interface

/// <summary>
/// using the DoSomthing interface, which the application supports.
/// </summary>
/// <param name="param">your name</param>
/// <returns>Hello 'your name'</returns>
public string DoSomthing(string param)
{
 return "Hello " + param;
}

  • Compile it

There it is, a plug in

3. PlugControlApp - Your uber cool application

Finally your application will also use 'design by interface' to implement the various plug-ins. I have built a small rig for this, which in this article i will only highlight the main points. As you application will handle things differently, and also i will include the projects zipped up for you to download.

This project will require the following using imports

using System.Reflection;
using interfaceLib; //this will describe the plug-in interface

The main routines were to load the plug in, and then use it. So lets review these

A. Loading in a plug-in (there are many different ways to do this), in my example project i store the loaded list of plug-ins in a List<Type>, and then store this in a listbox. (ListBox1)

/// <summary>
/// This will load in all the plug-in class, which
/// this application can support.
/// </summary>
/// <param name="location">The full location of the plug in.</param>
/// <returns>False, if it cannot load in any plug-in</returns>
private bool LoadPlugin(string location)
{
 bool rValue = false;
 try
 {
  Assembly a = Assembly.LoadFile(location);
  //now get all avalible publlic types.
  foreach (Type t in a.GetTypes())
  {
   //only interested in plublic classes.
   if (t.IsPublic && t.IsClass)
   {
    //does our application support the plug-in?
    if (IsSupportedInterface(t))
    {
     plugins.Add(t); //add this to the loaded plugins.
     rValue = true; //was able to load in a plug-in.
    }
   }
  }
 }
 catch (Exception ex)
 {
  //do nothing, could not load in
  //the dll, should have some logging code
  //here.
 }
 return rValue;
}

Remember you only want to be able to load in plug-ins which support your interfaces. (my load in function uses the following to do this).

/// <summary>
/// simple method to see if the plug as a interface which is supported.
/// </summary>
/// <param name="_plugin">plug in type. (class)</param>
/// <returns>True if this class can be supported.</returns>
private static bool IsSupportedInterface(Type _plugin)
{
 Assembly a = Assembly.GetAssembly(typeof (Plugin));

 foreach (Type t in a.GetTypes())
 {
  foreach (Type iType in _plugin.GetInterfaces())
  {
   if (t.Name == iType.Name)
    return true;
  }
 }
 return false;
}

B. Now as we loaded in the plug-in, you can now invoke the new way of processing the Dosomething method

firstly what I did here was to gain a reference to the class type,

//the actual class need to be referenced
Type ob = (Type) listBox1.SelectedItem;

this will allow us to create an instance of the class, using this method to create the object

/// <summary>
/// Create an instance of the object
/// </summary>
/// <typeparam name="T">Type of the object to create</typeparam>
/// <param name="_plugIn">The class as a type.</param>
/// <returns>a created instance of this class.</returns>
private static T createInsatance<T>(Type _plugIn) where T : class
{
 return (T) Activator.CreateInstance(_plugIn);
}

the following code uses some functions to create the instance (above) of the required object and then it runs the method. note that the interface is being used to do this

//note the interface
DoSomething p = createInsatance<DoSomething>(ob);
//get the user input from a textbox
TextBox text = GetControlByName<TextBox>("userInput");
if (text != null)
{
 //program against the plug-in using the
 //interface
 MessageBox.Show(p.DoSomthing(text.Text), p.Name);
}

So what does this all give you??

 

 

Files:

interfaceLib.zip (9.38 kb)

PlugControlApp.rar (39.26 kb)

Plugin.rar (11.16 kb)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

A bit of Active Directory

Published 3/17/2008 by Dave in dotNet
Tags:

Recently I have been working with the Active Directory, using .Net and LDAP to query this data store for information. As I am a little new to this I did not know what information was stored about a user on the AD. I found examples which showed how to filter on the AD, returning a sub set of columns (properties), which is OK, if you know the name of the columns you want.

So here is a easy way to find ALL the information stored about a certain single user:

public static void test()
{
    string userName = "userName";
    DirectorySearcher search = new DirectorySearcher();
    //search for the user via his/hers log on
    search.Filter = String.Format("(SAMAccountName={0})", userName);
    //load all the properties
    search.PropertiesToLoad.Add("*");

    SearchResult result = search.FindOne();
    //output ALL the information found about the user.
    foreach (System.Collections.DictionaryEntry entry in result.Properties)
    {
        Console.Write(entry.Key + " = ");
        int i = result.Properties[entry.Key.ToString()].Count;
        for (int b = 0; b < i; b++)
        {
            Console.WriteLine(result.Properties[entry.Key.ToString()][b].ToString());
        }
        Console.WriteLine("");
    }
}

I cannot show you a screen shot, as that would be silly of me... but now you can go to this awesome article and be able to create some cool code.

http://www.codeproject.com/KB/system/QueryADwithDotNet.aspx

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

It can be helpful to know how and what ports your application connects to the MS SQL server. Ok maybe not, but i was in a pickle and needed to find this information out. What I was looking for was all the connections I had open to a SQL server from a certain connection pool. I came up with the following script...

Declare  @dave_sp_who3 table
(
    SPID INT,
    [Status] VARCHAR(100) NULL,
    [Login] SYSNAME NULL,
    HostName SYSNAME NULL,
    BlkBy SYSNAME NULL,
    DBName SYSNAME NULL,
    Command VARCHAR(100) NULL,
    CPUTime INT NULL,
    DiskIO INT NULL,
    LastBatch VARCHAR(100) NULL,
    ProgramName VARCHAR(100) NULL,
    SPID2 INT,
      RequestID int
)
 
INSERT @dave_sp_who3 EXEC sp_who2
 
SELECT distinct * --client_tcp_port, local_tcp_port
FROM sys.dm_exec_connections
WHERE session_id in (
      SELECT SPID FROM @dave_sp_who3
    WHERE [Login] = 'loginName')
 order by client_tcp_port

Replcace the login name with the user ID or the connection ID, and this will now list all open connections you have and will show how they are connected. IE

You can glem the following great information

Connection type: [Named Pipes, TCP, Shared Memory]
IP address of the Client
TCP port number of both the client and SQL server

 How does this script work?

 I use the sp_who2, to list all the active connections, which is inturn stored in a temp table  (@dave_sp_who3 table). This table is filtered on the application pool im interested with and used with the sys.dm_exec_connections to gain the rest of the information.

 nice and simple :)

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5