Tuesday, January 4, 2011

Log4Net vs Enterprise Library

In development after deploying application to test servers or production lots of bugs can be discovered only if You implemented a good logging or some logging at all.

I have found that there is 2 products dominating that is Log4Net and Ent.Lib Logging

Today I wanted to test only performance.

Used versions:
Log4Net 1.2.10
Microsoft Enterprise Library 5.0

Visual Studio 2010 Premium
.Net framework 3.5 (Sharepoint does not work with 4.0)

Testing process:
Creating console application that creates 10000 log Info level entries and measure time.
Creating Test Code

class Program
{
static void Main(string[] args)
{
DateTime d = DateTime.Now;
for (int n = 0; n < 10000; n++)
{
//Logging goes here
}
DateTime d2 = DateTime.Now;
Console.WriteLine(string.Concat("Finished: ", (d2-d).Milliseconds, "ms"));
Console.ReadKey();
}
}

Log4Net
1 Adding reference to
bin\net\2.0\release\log4net.dll
2 Configuring

<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>
<log4net>
<param name="File" 
<appender name="LogFileAppender" type="log4net.Appender.FileAppender,log4net" >
value="c:\\!\\log4net.txt" />
<param name="AppendToFile" value="true" />
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] &lt;%X{auth}&gt; - %m%n" />
</layout>
</appender>
<root>
<priority value="ALL" />
<appender-ref ref="LogFileAppender" />
</root>
<category name="Log4NetTest.Program">
<priority value="ALL" />
</category>
</log4net>
</configuration>

3. Code

class Program
{
private static readonly ILog log = LogManager.GetLogger(typeof(Program));
static void Main(string[] args)
{
XmlConfigurator.Configure();
DateTime d = DateTime.Now;
for (int n = 0; n < 10000; n++)
{
//Logging goes here
log.Info(n);
}
DateTime d2 = DateTime.Now;
Console.WriteLine(string.Concat("Finished: ", (d2-d).Milliseconds, "ms"));
Console.ReadKey();
}
}

Microsoft Enterprise Library 5.0

1. Adding reference to Ent.Lib
Microsoft Enterprise Library 5.0\Bin\Microsoft.Practices.EnterpriseLibrary.Logging.dll
2. Configuring
image_thumb
3. Code

static void Main(string[] args)
{
DateTime d = DateTime.Now;
for (int n = 0; n < 10000; n++)
{
//Logging goes here
Logger.Write(n);
}
DateTime d2 = DateTime.Now;
Console.WriteLine(string.Concat("Finished: ", (d2 - d).Milliseconds, "ms"));
Console.ReadKey();
}

Results for 10K records (Keeping Log files after each test)
Nr   Log4Net    Ent.Lib
1     218ms      515ms
2     234ms      468ms
3     203ms      390ms
4     249ms      640ms
5     234ms      390ms

Results for 1M records(Deleted Log files after each test)
Nr   Log4Net    Ent.Lib
1     107ms      253ms
2     436ms      742ms
3     279ms      241ms
4     216ms      350ms
5     342ms      240ms

Conclusion:
Log4Net is lighter and faster but it lacks configuration manager like Ent.Lib provides. To make configuration file I had to google around and search for examples. Ent.Lib is a little slower, but configuration tool it compensates that with very easy way to create logging for Your application.

Monday, January 3, 2011

Exporting SharePoint web and Importing to same SiteCollection (part 2)

Read (Part 1) before

The problem when You need to change web Url while importing must be solved manualy.

Add Event handler to import procedure.

import.Started += new EventHandler<SPDeploymentEventArgs>(OnSiteImportStarted);
private void OnSiteImportStarted(object sender, SPDeploymentEventArgs args)
{
  SPImportObjectCollection rootObjects = args.RootObjects;
  if (rootObjects.Count != 0)
  {
   if (rootObjects.Count != 1)
   {
    for (int i = 0; i < rootObjects.Count; i++)
    {
     if (rootObjects[i].Type == SPDeploymentObjectType.Web)
     {
      rootObjects[i].TargetParentUrl = m_webParentUrl;
      rootObjects[i].TargetName = m_webName;
      return;
     }
    }
   }
   else
   {
    rootObjects[0].TargetParentUrl = m_webParentUrl;
    rootObjects[0].TargetName = m_webName;
   }
  }
 }

Thanks to:
http://blog.falchionconsulting.com/

Thursday, December 30, 2010

Large Xml, Sharepoint Export file Manifest.xml

Today I’m dealing with task to copy Sharepoint Web and SubWebs to the same server with selective data where SubWebs contains no ListItems.

After exporting a Web and Subwebs with option FileCompression = false, it created a 282MB large Manifest.xml.

I have tried to open it using Notepad++ It was so slow that I had to kill process to continue work, next opened with VS2010 that was much better, but to manually remove lines would take ages.

So I googled for another solution and found few programs that could manage large xml. 010Editor, XMLSpy, didn’t try any of them.

After 2 hours of searching for solution I wrote program in .NET that did it very well and took only 4 minutes to complete.

public static void StreamCustomerItem(string uri)
{
  using (XmlReader reader = XmlReader.Create(uri))
  {
    XmlWriterSettings xws = new XmlWriterSettings();
    xws.OmitXmlDeclaration = true;
    xws.Indent = true;
    xws.CheckCharacters = false;
    using (XmlWriter xw = XmlWriter.Create("Manifest.xml", xws))
    {
      XElement name = null;
      while (reader.Read())
      {
        switch (reader.NodeType)
        {
          case XmlNodeType.Element:
            if (reader.Name == "SPObject")
            {
              name = XElement.ReadFrom(reader) as XElement;
              if (name.Attribute(XName.Get("ObjectType")).Value == "SPListItem")
              {

//Excluding unwanted content
if (name.Attribute(XName.Get("ParentWebUrl")).Value.StartsWith("/SubwebUrl/")) continue;

              }
              name.WriteTo(xw);
              break;
            }
            xw.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
            xw.WriteAttributes(reader, true);
            if (reader.IsEmptyElement)
            {
              xw.WriteEndElement();
            }
            break;
          case XmlNodeType.Text:
            xw.WriteString(reader.Value);
            break;
          case XmlNodeType.Whitespace:
          case XmlNodeType.SignificantWhitespace:
            xw.WriteWhitespace(reader.Value);
            break;
          case XmlNodeType.CDATA:
            xw.WriteCData(reader.Value);
            break;
          case XmlNodeType.EntityReference:
            xw.WriteEntityRef(reader.Name);
            break;
          case XmlNodeType.XmlDeclaration:
          case XmlNodeType.ProcessingInstruction:
            xw.WriteProcessingInstruction(reader.Name, reader.Value);
            break;
          case XmlNodeType.DocumentType:
            xw.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"), reader.Value);
            break;
          case XmlNodeType.Comment:
            xw.WriteComment(reader.Value);
            break;
          case XmlNodeType.EndElement:
            xw.WriteFullEndElement();
            break;
        }
      }
    }
  }
}

Thanks to:
MSDN
MSDN Mark Fussell's WebLog

Tuesday, December 28, 2010

Exporting SharePoint web and Importing to same SiteCollection

There is built in feature in stsadm to Export and Import sites and webs, It is very useful and almost always sufficient, but there can be more complex scenarios when it is just not enough then there is way to do this in code.
private static string Export(string siteURL, string fileToExport)
{
  SPExportSettings exportSettings = new SPExportSettings();
  exportSettings.AutoGenerateDataFileName = true;
  exportSettings.ExportMethod = SPExportMethodType.ExportAll;
  exportSettings.SiteUrl = siteURL;
  exportSettings.IncludeSecurity = SPIncludeSecurity.None;
  exportSettings.IncludeVersions = SPIncludeVersions.CurrentVersion;
  exportSettings.CommandLineVerbose = true;
  exportSettings.FileLocation = fileToExport;
 
  SPExportObject exportObject = new SPExportObject();
  exportObject.ExcludeChildren = false;
  exportObject.Type = SPDeploymentObjectType.Web;
 
  using (SPSite site = new SPSite(siteURL))
  {
    using (SPWeb web = site.OpenWeb(siteURL.Substring(site.Url.Length, siteURL.Length - site.Url.Length)))
    {
      exportObject.Id = web.ID;
    }
  }
  exportObject.IncludeDescendants = SPIncludeDescendants.All;
  exportSettings.ExportObjects.Add(exportObject);
  SPExport export = new SPExport(exportSettings);
  export.Run();
  return exportSettings.FileLocation + "\\" + exportSettings.BaseFileName;
}
private static void Import(string siteURL, string fileToImport)
{
  SPImportSettings importSettings = new SPImportSettings();
  importSettings.BaseFileName = System.IO.Path.GetFileName(fileToImport);
  importSettings.FileLocation = System.IO.Path.GetDirectoryName(fileToImport);
  importSettings.SiteUrl = siteURL;
  importSettings.RetainObjectIdentity = false;
  importSettings.IncludeSecurity = SPIncludeSecurity.None;
  importSettings.UpdateVersions = SPUpdateVersions.Ignore;
  importSettings.UserInfoDateTime = SPImportUserInfoDateTimeOption.None;
  importSettings.SuppressAfterEvents = true;
  importSettings.CommandLineVerbose = true;
  SPImport import = new SPImport(importSettings);
  import.Run();
}
 
Continiunes (Part 2) 

Tuesday, December 21, 2010

SharePoint 2007 / WSS 3.0 Task Alert Issue

There is lots of blogs already about this, but I have a little different scenario.

First I have exported site using stsadm –o export and then imported it to the same server as subsite. The site contained a list called UserTasks it have a contentType that inherits from Tasks.

The issue is that user does not get email alerts when a task has been assigned to. The original site still can send email notifications.

Sharepoint have a 4 tables in database related to this:
ImmedSubscriptions  (Stores the alerts for emails that are sent immediately when changes occur)
SchedSubscriptions (Stores daily or weekly scheduled alerts)
EventLog (This table contains events for which only non-immediate alerts exist)
EventCache (This table contains a list of site events for which users have requested alerts. WSS inserts events into this table as they occur)

Scenario how I have resolved this is following.

First thing I checked ImmedSubscriptions table and found that a record related to this list is not created by import procedure. Created this record manually by copying from original site and changed fields accordingly.

stsadm -o updatealerttemplates -url <SubsiteUrl> -f "c:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\xml\alerttemplates.xml" -LCID 1062

stsadm -o setproperty -pn job-immediate-alerts -pv "every 1 minutes" -url <SubsiteUrl>

restarted “Windows SharePoint Services Timer” service

And it worked! :)

 

Thanks to:
Mel Lota’s weblog
Daniel Pavelescu's Blog
sharepointalert.info

Friday, October 15, 2010

WSS 3.0 / Sharepoint Performance testing

 

“Why it is so slow ?”, “What is happening ?”, “Is it still working ?”

Visual Studio 2010 Premium have built in Performance testing tool “Profiler”. For most of projects it works fine, but when it comes to Workflows You cannot attach using Visual Studio to IIS worker process and debug it. You have to do it manually using command line:

VSPerfASPNetCmd.exe /s /o:profileName http://serverurl

You can find it in the filder:

%programfiles%\Microsoft Visual Studio 10.0\Team Tools\Performance Tools\

So it generates report in *.vsp file in working directory. Open it using Visual Studio 2010

This report allows to click through the Functions until You find the code line (if debug information is found) which caused the slow performance.

The bad thing I found is that time elapsed shows only in graph view. Later on You get information only about Exclusive and Inclusive samples.

I have successfully monitored page loads, events and even workflows so it is very useful tool for developers

image

WSS 3.0 / Sharepoint 2007 Multithreading

 

Today I am testing how multi threading will improve performance on different Sharepoint tasks

So the first thing to remember is, that SPSite and SPWeb are not thread safe and therefore have to create new instance of them in each Thread or there will be Sharepoint Exception

Microsoft.SharePoint.SPException: Attempted to make calls on more than one thread in single threaded mode.