잊지 않겠습니다.

'.netframework'에 해당되는 글 3건

  1. 2009.02.12 IronPython 2.0 2
  2. 2009.02.10 System.Reflection을 이용한 Assembly Remote Runner
  3. 2009.02.09 ExceptionToHtml Class

IronPython 2.0

.NET Framework 2009. 2. 12. 22:34
예전부터 관심이 있었지만, 일단 깔아두기만 하고 간단한 string 처리 부분만 알아보고 있다가.. 이번에 회사에서 계속해서 바뀌게 되는 Scheduler 내용을 좀 편하게 업데이트해보고자 사용해봤다. 

일단, 첫 느낌은 매우 만족. 
다른 것보다 .NET Class 들을 간단히 들고와서 모두 사용할 수 있기때문에 너무나 편하긴 한데. 
아직까지는 좀 걸리는 점이 많아서 조금은 아쉬운 상태. 

무엇보다도. 개인적으로 가장 많이 사용하는 feedparser.py 에서 버그를 가지고 있다. 
CPython에서 동작되는 것과 다르게 동작이 되고, 에러가 나서 MIME mail Message를 해석하지를 못한다. 

다른 것들은.. 개인적으로 Python에 대한 지식이 미천하여 사용은 그다지 잘 못해봤지만 Windows Scheduler에 올릴 간단한 Script 적 프로그램을 Compile 시키는 것보다는 훨씬 나은 선택임은 틀림없을 것 같다. 

IronPython을 사용하는 가장 큰 이유가 될 .NET Library Load는 다음과 같다.
1. clr의 Import
2. clr.AddReference를 통해 Library 파일 로드 (파일 이름대로 Load를 시킨다.)
3. namespace를 이용해서 필요한 Class들을 로드시키면 된다. 

import clr
clr.AddReference('MyLIB1.dll')
clr.AddReference('MyLIB2.dll')
clr.AddReference('MyLIB3.dll')

import System
from com.hostway.lib.Configuration import Configuration
from com.hostway.lib.Database import CSDatabase
from com.hostway.lib.Database.Structure import SmsQueueItem
from com.hostway.lib.Communications.SKT.SKTComm import SmsSender

Posted by Y2K
,
Unit Test에서 사용되는 NUnit를 보면 [Test] attribute와 [TestFixture] attribute를 이용해서 각각의 Test Class와 Method를 모두 얻어내게 된다.

먼저, Assembly의 Load는 간단하게 Assembly의 static method를 통해서 얻어올 수 있다.

Assembly assem = Assembly.LoadFile(PlugInFileName);

여기에서 Assembly의 각 Class의 Attribute의 조건을 얻어오기 위해서 static class를 하나 생성

public static bool HasAttribute(MemberInfo member, string attrName, bool inherit)
{
    object[] attributes = member.GetCustomAttributes(inherit);
    foreach(Attribute attribute in attributes)
    {
        if(IsInstanceOfType(attrName, attribute))
        {
            System.Diagnostics.Debug.WriteLine(attribute);
            return true;
        }
    }
    return false;
}

얻어진 결과를 linq를 이용해서 검색. (이런 곳에서도 linq는 이용 가능하다. ^^)

var types = from t in assem.GetTypes()
            where Reflect.HasAttribute(t, typeName, true) 
            select t;

이렇게 얻어온 Class를 Activator를 이용해서 Instance를 생성해주면 외부 assembly가 가지고 있는 class의 동적 이용 및 NUnit과 비슷한 동작을 하는 것이 가능해진다. 

ISYNCmailPlugIn plugIn = Activator.CreateInstance(type) as ISYNCmailPlugIn;

Remote에서 사용하게 될 경우에 장점은 다음과 같다. 
1. Compile시에 Dll이 필요하지 않다. 
: 동적 load가 되기 때문에 잦은 변경이 있는 lib인 경우에 사용이 편리하다. 

2. 특정한 Interface나 Attribute를 가지고 있는 경우에 외부에서 사용이 가능하다.
Posted by Y2K
,
Exception을 mail로 보내야지 될 때가 많아서, Exception handler를 간단하게 제작
가장 Key Point는 HttpContext static Member를 이용해서, web에서 발생된 Error도 같이 표현하고 있다는 것이 가장 좋은 점 같다. 

    /// <summary>HtmlError Object.</summary>
    public class ExceptionToHtmlConverter
    {
        public enum ErrorInfoType
        {
            Exception,
            Context
        };
        private delegate string ErrorRendererDelegate(string headerString, NameValueCollection collection);
        static private Hashtable GetErrorInfo(Exception exception)
        {
            Hashtable errorTable = new Hashtable();
            if(exception == null)
            {
                throw new ArgumentNullException("exception");
            }

            // Populate Error Information Collection
            ArrayList errorInfoArray = new ArrayList();
            while(exception != null)
            {

                // Populate Error Information Collection
                NameValueCollection errorInfo = new NameValueCollection();
                errorInfo.Add("Exception Type", exception.GetType().ToString());
                errorInfo.Add("Message", exception.Message);
                errorInfo.Add("Source", exception.Source);
                errorInfo.Add("TargetSite", exception.TargetSite.ToString());
                errorInfo.Add("StackTrace", exception.StackTrace);

                errorInfoArray.Add(errorInfo);
                exception = exception.InnerException;
            }

            errorTable.Add(ErrorInfoType.Exception, errorInfoArray.ToArray());

            if(HttpContext.Current != null)
            {
                Hashtable info = new Hashtable();

                info.Add("QueryString", HttpContext.Current.Request.QueryString);
                info.Add("Form", HttpContext.Current.Request.Form);
                info.Add("Cookies", HttpContext.Current.Request.Cookies);
                info.Add("Session", HttpContext.Current.Session);
                info.Add("Server Variables", HttpContext.Current.Request.ServerVariables);

                errorTable.Add(ErrorInfoType.Context, info);
            }

            return errorTable;

        }
        /// <summary>Returns HTML an formatted error message.</summary>
        static public string GetHtmlError(Exception Ex)
        {
            if(Ex == null)
            {
                throw new ArgumentNullException("Ex");
            }

            // Error Message Header
            StringBuilder sb = new StringBuilder();
            Hashtable errorTable = GetErrorInfo(Ex);
            ErrorRendererDelegate renderer = CollectionToHtmlTable;

            if(HttpContext.Current != null)
            {
                sb.AppendFormat("<font face=\"Arial\" size=\"4\" color=\"red\">An error occurred at {0}<br><font size=\"3\">&nbsp;&nbsp;&nbsp;&nbsp;{1}</font></font><br><br>", HttpContext.Current.Request.Url.ToString(), Ex.Message);
            }

            // Populate Error Information Collection
            foreach(NameValueCollection errorInfo in errorTable[ErrorInfoType.Exception] as object[])
            {
                // Error Information
                sb.Append(renderer("Error Information", BuildCollection(errorInfo)));
            }

            if(errorTable[ErrorInfoType.Context] != null)
            {
                Hashtable info = errorTable[ErrorInfoType.Context] as Hashtable;

                foreach(DictionaryEntry entry in info)
                {
                    sb.AppendFormat("<BR><BR>\n{0}", renderer(entry.Key as string, BuildCollection(entry.Value as ICollection)));
                }
            }

            return sb.ToString();
        }

        /// <summary>Returns HTML an formatted error message.</summary>
        static public string GetTextError(Exception Ex)
        {
            if(Ex == null)
            {
                throw new ArgumentNullException("Ex");
            }

            // Error Message Header
            StringBuilder sb = new StringBuilder();
            Hashtable errorTable = GetErrorInfo(Ex);
            ErrorRendererDelegate renderer = CollectionToTextTable;

            // Populate Error Information Collection
            foreach(NameValueCollection errorInfo in errorTable[ErrorInfoType.Exception] as object[])
            {
                // Error Information
                sb.Append(renderer("Error Information", BuildCollection(errorInfo)));
            }

            if(errorTable[ErrorInfoType.Context] != null)
            {
                Hashtable info = errorTable[ErrorInfoType.Context] as Hashtable;

                foreach(DictionaryEntry entry in info)
                {
                    sb.AppendFormat("\r\n{0}", renderer(entry.Key as string, BuildCollection(entry.Value as ICollection)));
                }
            }

            return sb.ToString();
        }

        #region Private Methods
        static private string CollectionToHtmlTable(string headerString, NameValueCollection collection)
        {

            // Heading Template
            const string heading = @"
  <tr>
    <td bgcolor=""#666666"" colspan=""2"">
      <font face=""Arial"" color=""white""><b>&nbsp;{0}</b></font>
    </td>
  </tr>
";
            // <TD>...</TD> Template
            const string TD = "<td><font face=\"Arial\" size=\"2\"><!--VALUE--></font></td>";

            StringBuilder sb = new StringBuilder();
            // Table Header
            sb.Append("\n<table width=\"100%\" bgcolor=\"#d1d9e4\" cellspacing=\"1\" cellpadding=\"3\">\n");
            sb.AppendFormat(heading, headerString);

            sb.AppendFormat("  <tr bgcolor=\"#d0d0d0\">\n");
            sb.AppendFormat("    {0}\n", TD.Replace("<!--VALUE-->", "&nbsp;<b>Name</b>"));
            sb.AppendFormat("    {0}\n", TD.Replace("<!--VALUE-->", "&nbsp;<b>Value</b>"));
            sb.Append("  </tr>\n");

            // No Body? -> N/A
            if(collection.Count == 0)
            {
                collection = new NameValueCollection();
                collection.Add("N/A", "");
            }

            // Table Body
            for(int i = 0; i < collection.Count; i++)
            {
                sb.AppendFormat("  <tr valign=\"top\" bgcolor=\"{0}\">\n", (i % 2 == 0) ? "white" : "#f4f4f4");
                sb.AppendFormat("    {0}\n", TD.Replace("<!--VALUE-->", collection.Keys[i]));
                sb.AppendFormat("    {0}\n", TD.Replace("<!--VALUE-->", CleanHtml(collection[i])));
                sb.Append("  </tr>\n");
            }

            // Table Footer
            sb.Append("</table>");

            return sb.ToString();
        }
        static private string CollectionToTextTable(string headerString, NameValueCollection collection)
        {

            // Heading Template
            const string heading = "{0}\r\n\r\n";


            StringBuilder sb = new StringBuilder();
            sb.AppendFormat(heading, headerString);


            // No Body? -> N/A
            if(collection.Count == 0)
            {
                collection = new NameValueCollection();
                collection.Add("N/A", "");
            }

            // Table Body
            for(int i = 0; i < collection.Count; i++)
            {
                sb.AppendFormat(" {0} : {1}\r\n", collection.Keys[i], collection[i]);
            }

            return sb.ToString();
        }
        
        static private NameValueCollection BuildCollection(ICollection collection)
        {
            // Overload for HttpCookieCollection collection.
            // Converts HttpCookieCollection to NameValueCollection
            if(collection == null)
            {
                collection = new NameValueCollection();
            }
            NameValueCollection nvCollection = new NameValueCollection();
            IEnumerator en = collection.GetEnumerator();

            object entry;
            while(en.MoveNext())
            {
                entry = en.Current;

                if(collection is HttpCookieCollection)
                {
                    nvCollection.Add(entry.ToString(), (collection as HttpCookieCollection)[entry.ToString()].Value);
                }
                    // Min
                    // CANNOT_MAKE_TEST_CONDITION
                else if(collection is HttpSessionState)
                {
                    nvCollection.Add(entry.ToString(), (collection as HttpSessionState)[entry.ToString()].ToString());
                }
                    // END-CANNOT_MAKE_TEST_CONDITION
                else if(collection is NameValueCollection)
                {
                    if(entry != null)
                    {
                        nvCollection.Add(entry.ToString(), (collection as NameValueCollection)[entry.ToString()].ToString());
                    }
                }
                else
                {
                    throw new NotSupportedException(collection.GetType().ToString());
                }
            }
            return nvCollection;
        }


        static private string CleanHtml(string html)
        {
            // Cleans the string for HTML friendly display
            return (html.Length == 0) ? "" : html.Replace("<", "&lt;").Replace("\r\n", "<BR>").Replace("&", "&amp;").Replace(" ", "&nbsp;");
        }
        #endregion
    }

Posted by Y2K
,