Spiga

Don't want to GAC log4net.dll

In this example I'll use log4net

I managed to get logging working by dropping the log4net release dll in the _app_bin directory found on my dev system in C:\Inetpub\wwwroot\wss\VirtualDirectories\8081\

The 8081 part is the same as the port I have serving up the sites I am currently playing with.

This is nice to know in a dev environment as you might not want to go to the trouble of GACing (is that a verb?) everything you deliver in you solution.

OK that's fine how do I use it?

My working example extends my previous post on application pages.
Add this code to your web.config (which should be empty at the moment)


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>

<log4net debug="true">
<root>
<level value="ERROR" />
<!-- priority value can be set to ALL|INFO|WARN|ERROR -->
<priority value="ALL" />
<appender-ref ref="AdoNetAppender" />
</root>

<!-- Define some output appenders -->
<appender name="AdoNetAppender" type="log4net.Appender.AdoNetAppender">
<bufferSize value="1" />
<connectionType value="System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<connectionString value="data source=VSMOSSCOMBO;initial catalog=WSS_Log;integrated security=true;" />
<commandText value="INSERT INTO dbo.ExceptionLog ([Date],[Thread],[Level],[Logger],[Message],[Exception],[ApplicationUser]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception, @user)" />
<parameter>
<parameterName value="@user" />
<dbType value="string" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%X{user}" />
</layout>
</parameter>
<parameter>
<parameterName value="@log_date" />
<dbType value="DateTime" />
<layout type="log4net.Layout.RawTimeStampLayout" />
</parameter>
<parameter>
<parameterName value="@thread" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%thread" />
</layout>
</parameter>
<parameter>
<parameterName value="@log_level" />
<dbType value="String" />
<size value="50" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%level" />
</layout>
</parameter>
<parameter>
<parameterName value="@logger" />
<dbType value="String" />
<size value="255" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%logger" />
</layout>
</parameter>
<parameter>
<parameterName value="@message" />
<dbType value="String" />
<size value="4000" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%message" />
</layout>
</parameter>
<parameter>
<parameterName value="@exception" />
<dbType value="String" />
<size value="2000" />
<layout type="log4net.Layout.ExceptionLayout" />
</parameter>
</appender>
</log4net>
</configuration>


This web.config points to a database called WSS_Log with a table called ExceptionLog. Here is the Create Script for the table.


CREATE TABLE [dbo].[ExceptionLog](
[ExceptionLogKey] [int] IDENTITY(1,1) NOT NULL,
[Guid] [uniqueidentifier] NULL,
[ApplicationUser] [nvarchar](255) NULL,
[Date] [datetime] NULL,
[Thread] [nvarchar](255) NULL,
[Level] [nvarchar](50) NULL,
[Logger] [nvarchar](255) NULL,
[Message] [nvarchar](4000) NULL,
[Exception] [nvarchar](2000) NULL,
PRIMARY KEY CLUSTERED
(
[ExceptionLogKey] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]


Add this to your AssemblyInfo.cs


[assembly: log4net.Config.XmlConfigurator(ConfigFile = "Web.config", Watch = true)]

Now you can use the Log but for completeness make your Default.aspx.cs look like this.


using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using log4net;
using log4net.Core;

namespace MOSS.Web.Application.Basic
{

[CLSCompliant(false)]
public class Default : LayoutsPageBase
{
private static readonly ILog log = LogManager.GetLogger("Logger");

// add control fields to match controls tags on .aspx page
protected Label lblSiteTitle;
protected Label lblSiteID;

protected override void OnLoad(EventArgs e)
{
log.Debug("OnLoad");

// get current site and web
SPSite siteCollection = this.Site;
SPWeb site = this.Web;

// program against controls on .aspx page
lblSiteTitle.Text = site.Title;
lblSiteID.Text = site.ID.ToString().ToUpper();
}
}
}

Application Pages

The Awesome power of Application Pages

A useful link http://msdn.microsoft.com/en-us/library/bb418732.aspx

In VS.Net 2005 on your MOSS Server Development Environment create an empty Sharepoint Project. (I called mine MOSS.Web.Application)
Add a reference to Microsoft.SharePoint (Windows® SharePoint® Services) v2.0.50727
In my environment its at C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\ISAPI\Microsoft.SharePoint.dll

(If you can't work out which one to choose add a webpart to the solution then delete the Webpart bits that were just added)


Add a directory named Templates to the project root
Add a directory named LAYOUTS to the Templates Directory you just made
Add a directory named {Your Application Page Directory} to LAYOUTS (I made one called Basic)
Under {Your Application Page Directory} add a file called default.aspx with this code in it.




<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Assembly Name="MOSS.Web.Application, Version=1.0.0.0, Culture=neutral, PublicKeyToken={PUBLIC KEY TOKEN}"%>

<%@ Page Language="C#" MasterPageFile="~/_layouts/application.master"
Inherits="MOSS.Web.Application.Basic.Default" %>



<asp:Content ID="Main" runat="server" contentplaceholderid="PlaceHolderMain" >
Site Title: <asp:Label ID="lblSiteTitle" runat="server" />
<br/>
Site ID: <asp:Label ID="lblSiteID" runat="server" />
</asp:Content>

<asp:Content ID="PageTitle" runat="server"
contentplaceholderid="PlaceHolderPageTitle" >
Hello World
</asp:Content>

<asp:Content ID="PageTitleInTitleArea" runat="server"
contentplaceholderid="PlaceHolderPageTitleInTitleArea" >
The Quintessential 'Hello World' of Application Page
</asp:Content>


Under {Your Application Page Directory} add a file called default.aspx.cs with this code in it.


using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

namespace MOSS.Web.Application.Basic
{

[CLSCompliant(false)]
public class Default : LayoutsPageBase
{

// add control fields to match controls tags on .aspx page
protected Label lblSiteTitle;
protected Label lblSiteID;

protected override void OnLoad(EventArgs e)
{

// get current site and web
SPSite siteCollection = this.Site;
SPWeb site = this.Web;

// program against controls on .aspx page
lblSiteTitle.Text = site.Title;
lblSiteID.Text = site.ID.ToString().ToUpper();
}
}
}


Go to your project's WSP View and open manifest.xml making sure this code is in there




<?xml version="1.0" encoding="utf-8"?>
<Solution SolutionId="ce340c94-3b75-4abd-9a2d-537b8db6ada5" xmlns="http://schemas.microsoft.com/sharepoint/">
<Assemblies>
<Assembly Location="MOSS.Web.Application.dll" DeploymentTarget="GlobalAssemblyCache" />
</Assemblies>
<TemplateFiles>
<TemplateFile Location="LAYOUTS\Basic\default.aspx" />
<TemplateFile Location="LAYOUTS\Basic\Default.aspx.cs" />
<TemplateFile Location="LAYOUTS\Basic\Web.config" />
</TemplateFiles>
</Solution>


In the Project's Properties on the Debug Page put the url to the MOSS Site you wish to deploy to.

Once you have done that go to the Build menu and Deploy your Project

You will find it at {Your Sharepoint url}/_layouts/{Folder}/{Page}

How to get the PublicKeyToken of an Assembly

Can't find the PublicKeyToken of an Assembly?

Here is how.

Open the Visual Studio Command Prompt
type sn -T {target path} where {target path} is the path to the assembly in question.
You will get the PublicKeyToken and be happy again

Themes in a nutshell (Simplest Example)

Ok...

  1. Go to your THEMES Folder on your Sharepoint site
    Mine is here
    C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\THEMES
  2. Copy one of the Precanned THEME Directories (I used GRANITE) and Rename it to MYTHEME (Or whatever you want it to be)
  3. Open your new MYTHEME Directory and sort the contents by type.
  4. Delete all the gif files.
  5. Rename the INF file (GRANITE.INF) to MYTHEME.INF
  6. Open MYTHEME.INF
  7. Replace the old theme name (Granite) with your new theme name (MYTHEME)
    It will look something like this
    [info]
    title=MYTHEME
    codepage=65001
    version=3.00
    format=3.00
    readonly=true
    refcount=0

    [titles]
    1031=MYTHEME
    ... Shortened to save room.
    1054=MYTHEME
  8. Save and close it.
  9. Open theme.css and delete its contents.
  10. Then add this css code

    .ms-bannerframe,.mrGRHeaderBackGround, .ms-storMeFree
    {
    background-image:url("logo.gif");
    background-repeat:no-repeat;
    height:89px;
    background-color:#FFFFFF;
    }
  11. Save and close it.
  12. Open Paint and make a file called logo.gif and save it in your MYTHEME directory.
  13. Find and open the SPTHEMES.XML file
    Mine is here.
    C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS\1033
  14. You will see a bunch of <Templates> tags.
  15. Copy and paste one of them and edit it to look like this
    <Templates>
    <TemplateID>MYTHEME</TemplateID>
    <DisplayName>My Theme</DisplayName>
    <Description>Theme created specifically for ME</Description>
    <Thumbnail>images/thnone.gif</Thumbnail>
    <Preview>images/thnone.gif</Preview>
    </Templates>
    The image THNONE.GIF is found in the C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\IMAGES directory. If you want a different image for your thumbnail you just need to put it in the same directory as THNONE.GIF and reference it in SPTHEMES.XML.

  16. Save and close it.
  17. Once you are done you just need to go to your Sharepoint Site Settings -> Site Themes and select "My Theme" from the list.
  18. Your site will get your new logo at the top.

Themes

The first thing that every customer wants with a COTS product is to make it not look like an out of the box product. MOSS looks like a Microsoft product...the default theme has the blue that seems to belong to Microsoft now, just like they invented English (US)...God praise 'em for their ingenuity.

Anyway as this seems to be the first thing I will have to do I guess I'll start documenting what I find and how I turn that knowledge into something useful.

Firstly this link has some pretty useful info about theme creation.
and here is some good stuff about sharepoint css

Turn off Friendly Errors

Thanks to Heather Solomon

While in development, the friendly error page that SharePoint displays when your page has an error can make debugging your master page issues very difficult. You can make an easy change to your Web config file for the site to turn friendly error messages off, therefore providing you with more useful information if your page breaks. Only do the following in a development environment, you would never want to turn off friendly error messages in a production environment. Also be sure to make a back up of the file prior to editing.

  1. On the Web server, navigate to the site directory:
    Local Drive:\Inetpub\wwwroot\wss\VirtualDirectories\[directory for site] (for example 84)
  2. Open Web.config in Notepad.
  3. Search for "CallStack". Change the CallStack status to "true".
    CallStack="true" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
  4. Search for "CustomErrors". Change the mode to "off".
    mode="Off" />
  5. Save and close the file.
Now when your site encounters an error, you will receive a .NET screen outlining the issue instead of the friendly SharePoint error screen. This is particularly useful with dealing with missing Content Placeholders and editing Master Pages. To turn friendly error messages back on, just walk through these steps setting the CallStack to false and CustomErrors mode to On.

The Beginning

It all starts with a ground swell, a revolution of corporate opinion, and a bottom line.

The company I work for has decided, for good or bad, to deploy Sharepoint (MOSS) into their environment, heralding a new and exciting era for corporate collaboration. Because we need it.

Anyway I'll try and document my experiences as completely as I can here so that you, the reader, might save some time and pain.