More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  Colin Borrowman's ShareP...ProfileFriendsBlogMore Tools Explore the Spaces community

Colin Borrowman's SharePoint Blog

Some things that took me too long to find or figure out...
June 10

Debugging "File Not Found. at System.Reflection.Assembly"

Have you ever deployed your application to SharePoint only to have one or more pages start failing to load with the infamous "File Not Found" error? Or even just the blank "Error" if you don't have extended error messages turned on?

File Not Found.   at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
   at System.Reflection.Assembly.Load(String assemblyString)
   at System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective)

It usually means you need to add a page reference to allow the page markup to load and resolve your page (or your binary needs to be somewhere it can find it.) Sometime you can figure out what it might be if you just added a new control or referenced some assembly in the page markup. But sometime you don't know and there aren't any good clues. So it happened to me again today and I decided to document the exact steps required to figure out what blew up.

Find a copy of the Fusion Log Viewer "FUSLOGVW.EXE." It probably will not be on your deployment server, I think its only installed with development software. I found two copies on my dev box:

C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\FUSLOGVW.EXE dated 9/23/2005 and
C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\FUSLOGVW.EXE dated 11/7/2007

1. Copy the more recent version to the deployment server and run FUSLOGVW.EXE

1. Click Delete All

2. Run IISRESET from a command prompt

3. Refresh or load the page you were getting an error on in your browser

4. Click the Refresh button in the Fusion Log Viewer

5. Start looking (from the bottom up) for log entry for App_Web_error.aspx...  This is the error page being loaded to tell you "Error"

viewer

6. Start looking at the next few items above it for the first assembly that is part of your project. Double click on each one to look at the log entry and see if any of them failed.

log

In my case, I found the dtSearchNetApi2 was trying to load but could not be found. It was being referenced by one of the assemblies being loaded. I need to put it in a location that is searched for binaries, or simply put it in the GAC. Sometimes just adding a page @Register to the markup is all you need. Fixing the problem is easy once you know what problem you are fixing.

May 14

Get the list of Blocked File Extensions (file types)

This initially looked more difficult that it really is. I didn't find too many examples of how to do this. There appears to be an approach through the adminitrative SDK, since you maintain these through the central admin pages.  I also found some examples of the now obsolete SPGlobalConfig.BlockedFileTypes.

Turns out it is rather simple, even for a standard user. You can obtain a reference to the current WebApplication from the current site collection object and the blocked file extensions are available right there via BlockedFileExtensions.

Here is a sample test.aspx page that dumps the BlockedFileExtensions. The page itself is handy shell to quickly try out an SDK call or two. Just drop it inside C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS (or a sub folder) and access it with http:\\localhost\_layouts\(optional sub folder)\test.aspx

<%@ Page Language="C#" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml" >
<head>
    <title>Test</title>
</head>
<body>
<form id="form1" runat="server">
<%
    Microsoft.SharePoint.Administration.SPWebApplication webapp = SPContext.Current.Site.WebApplication;

    Response.Write("Blocked file extensions:<br />");
    foreach (string s in webapp.BlockedFileExtensions)
    {
        Response.Write(s + ",");
    }

    Response.Write("<br />"); 
%>
</form>
</body>
</html>

Results:

Blocked file extensions:
ade,adp,app,asa,ashx,asmx,asp,bas,bat,cdx,cer,chm,class,cmd,com,config,cpl,crt,csh,der,dll,exe,fxp,gadget,hlp,hta,htr,htw,ida,idc,idq,
ins,isp,its,jse,ksh,lnk,mad,maf,mag,mam,maq,mar,mas,mat,mau,mav,maw,mda,mdb,mde,mdt,mdw,mdz,msc,msh,msh1,msh1xml,
msh2,msh2xml,mshxml,msi,msp,mst,ops,pcd,pif,prf,prg,printer,pst,reg,rem,scf,scr,sct,shb,shs,shtm,shtml,soap,stm,url,vb,vbe,vbs,ws,
wsc,wsf,wsh,

April 02

SharePoint Vista Sidebar Gadget

Here's a new CodePlex project I've been working on in my spare time. This is a sample project showing how to create a Windows Vista Sidebar Gadget that communicates with a SharePoint site via web services.

http://www.codeplex.com/SharePointSidebar

It is in the proof-of-concept phase right now and it currently only works with windows or anonymous authentication. But it will continue to evolve to include basic and forms based authentication as well.

March 16

CSS filter DXImageTransform.Microsoft.Gradient has a very specific syntax

What's the difference between the following CSS entries? 

.sample1
{
    filter: progid:DXImageTransform.Microsoft.Gradient(startColorStr='#FEE9EC', endColorStr='#FFFFFF', gradientType= '0' );
}

 .sample2
{
    filter: progid:DXImageTransform.Microsoft.Gradient(startColorStr= '#FEE9EC', endColorStr='#FFFFFF', gradientType= '0' );
}

If you guessed that sample2 wouldn't work AND would break all CSS following it, you would be right. Huh? Notice the space following startColorStr= in sample2? How does one space break everything? Apparently the syntax for DXImageTransform.Microsoft.Gradient is so specific it does here. In IE all CSS following the entry stops working. In Firefox, some of the following CSS works, but isn't perfect.

March 05

Trouble using SPContext.Current in an IHttpAsyncHandler based http handler?

I have a http handler (ashx) that obtains content from a document library and renders a thumbnail of it, returning a jpeg stream back to the browser. Today while testing it in a deployment scenario, it was unable to get a site reference. (I have a class wrapped around the request to SPConext.Current that allows one mechanism to obtain a site reference whether running in development mode against http://localhost or in deployment mode against a site. It also handles dispose when necessary.)

It took too long to figure out what was happening, but apparently what was happening is that the handler got fired asynchronously and the SPContext could not obtain a reference to the current site. In this case my class tells it to go after the root site http://localhost, which on my deployment site didn't exist either.

I changed the class back to use IHttpHandler and it started working immediately. There must be some special way to use IHttpAsyncHandler and still be able to use SPContext.Current. I suspect it is possible to get a site reference through a specified URL, but that wouldn't work in my case. I'd prefer to use the async call, but in this case I can't seem to. Perhaps it would be possible to pass in the current site context as a parameter in the BeginProcessRequest...

This is one of those back burner projects to figure out...

March 03

Internet Explorer Developer Toolbar not working?

I had a problem today trying to get the Internet Explorer Developer Toolbar working in my virtual PC. I could get the toolbar button to appear in the toolbar, but clicking on it did nothing. I did the usual search and tried a few things related to other plug-ins, but couldn't get it working. A co-worker pointed me in the right direction: The Internet Explorer Enhanced Security Configuration

clip_image002

Un-checking this option and restarting IE got the toolbar working. 

February 26

Going back in time - Converting a VS2008 csproj to VS2005

I had the need to migrate an Ajax project created in VS2008 consisting of several class libraries back into a larger project created and built with VS2005. I'm not ready to convert that project into VS2008 just yet.

I preferred to just convert the csproj files back to VS2005 format and add them to the existing VS2005 project. I discovered a few easy steps that can allow you to do this. Note: I had already converted (most) of the project files to use .NET 2.0. If you are using Ajax extensions you will have to make your web.config align with this as well. Do this first in VS2008. Obviously if you are using any .NET 3.0 or .NET 3.5 features, this isn't going to work for you...

Next open the csproj file you want to change in Notepad.

Near the top is the Project node. If this contains ToolsVersion="3.5" remove this attribute:

<Project ToolsVersion="3.5" DefaultTargets=...

becomes

<Project DefaultTargets=...

A few lines down there is a <ProductVersion> node, change the value:

<ProductVersion>9.0.21022</ProductVersion>

becomes

<ProductVersion>8.0.50727</ProductVersion>

Near the bottom of the file, look for the <Import node, if it says MSBuildToolsPath, change "Tools" to "Bin" it:

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

becomes

<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

If there is another <Import node with an MSBuildExtensionsPath, delete this entire line.

Save the file and you should then be able to to open the file in VS2005. Don't double click on the file if you have both versions of Visual Studio installed, you will likely get the default VS2008 to load it.

February 12

Weird asmx web service assembly requirement in SharePoint

I was hit buy this problem again today and after going down the wrong road for too long, I (re)discovered the simple solution. I really don't understand why this is necessary but, when creating an asmx web service that lives under the _Layouts folder (a custom application page really), it is necessary to add an @assembly reference to the .asmx file. This isn't necessary when running in development or under plain old IIS. Note the .asmx sample file below:

<%@ WebService Language="C#" CodeBehind="EDVInfo.asmx.cs" Class="MyApp.EDVInfo" %>

This generates the following SharePoint error when you try to access the web service definition page:

Could not create type 'MyApp.EDVInfo'.   at System.Web.UI.SimpleWebHandlerParser.GetType(String typeName)
   at System.Web.UI.SimpleWebHandlerParser.GetTypeToCache(Assembly builtAssembly)
   at System.Web.Compilation.SimpleHandlerBuildProvider.GetGeneratedType(CompilerResults results)
   at System.Web.Compilation.BuildProvider.CreateBuildResult(CompilerResults results)
   at System.Web.Compilation.BuildProvider.GetBuildResult(CompilerResults results)
   at System.Web.Compilation.BuildManager.CompileWebFile(VirtualPath virtualPath)
   at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)
   at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile)
   at System.Web.Compilation.BuildManager.GetVPathBuildResult(HttpContext context, VirtualPath virtualPath)
   at System.Web.UI.WebServiceParser.GetCompiledType(String inputFile, HttpContext context)
   at System.Web.Services.Protocols.WebServiceHandlerFactory.GetHandler(HttpContext context, String verb, String url, String filePath)
   at System.Web.Script.Services.ScriptHandlerFactory.GetHandler(HttpContext context, String requestType, String url, String pathTranslated)
   at System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig)
   at System.Web.HttpApplication.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Adding one line, a reference to the assembly allows the web service to load the asmx and allow it to function. See the addition of the assembly name below:

<%@ Assembly Name="MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0000000000000000" %> 
<%@ WebService Language="C#" CodeBehind="EDVInfo.asmx.cs" Class="MyApp.EDVInfo" %>

I came across this trying to get an Ajax 1.0 project running in SharePoint. After tracing the traffic with Fiddler, I could see the asmx/jsdebug calls were failing. returning the same error above. It took me a while to recall this was a standard web service assembly resolution error and not something unique to my Ajax installation on SharePoint. This applies to http handlers as well (.ashx)

February 01

Sliced bread is now obsolete

Ted Pattison and friends have made an awesome utility available for free on codeplex.com. Not only does it make the creation of SharePoint development projects extremely easy, it encapsulates the best practices for organizing development projects related to SharePoint, provides shortcuts for common development and deployment activities and more.

I wish I had this utility a year ago!  Visit the codeplex project here: http://www.codeplex.com/stsdev 

Be sure to watch the screencasts on the releases page to get you up and running.

January 18

Javascript using DOM element property hasChildNodes

Here's one that surprised me this morning.  I was using this syntax a few times attempting to prevent entering a block if the div has no children:

// incorrect
i
f(this.mydiv.hasChildNodes)
{
       // do something
}

While debugging I discovered that if you use hasChildNodes without the parentheses, you actually get the function returned, not the boolean value you were expecting, which ends up being evaluated as true, entering the block you did not want to enter. Below is the correct syntax:

// correct
if(this.mydiv.hasChildNodes())
{
       // do something
}

The more I use Javascript object notation the more it feels like C# and you tend to forget you are not working in type-safe world... I noticed the MS Ajax library has some method to perform type checks on your own function parameters but I miss having it happen everywhere... Lesson learned.

January 16

My 3 Favorite Web Dev Tools

I've been doing quite a bit of Ajax and Web UI work the past few weeks and the following tools have proved invaluable.

1. Visual Studio 2008

If you are doing anything with JavaScript, stop everything and install this. This is the development environment to be using for this work. The new debugging features, intellisense and built in Ajax toolkit are tremendously helpful.

2. Fiddler

If you ever need to inspect what is crossing the wire, you need fiddler. It will expose everything you need to know about your browser/server communication. See one of my prior posts if you need to watch localhost traffic. www.fiddlertool.com.

3. Internet Explorer Development Toolbar

I didn't even know about this until 2 days ago when a co-worker suggested it. We were looking for some kind of tool to inspect the browser DOM as it existed in real time (as opposed to view source.)  I wish I had found this a couple years ago, it would have saved me from many "alert" iterations to figure out what was happening in the DOM.

Download:
http://www.microsoft.com/downloads/details.aspx?familyid=e59c3964-672d-4511-bb3e-2d5e1db91038&displaylang=en

Step by step getting started with it:
http://www.15seconds.com/issue/070208.htm

January 08

Fiddler / localhost / Vista

Here's an update on the prior fiddler tip if you are using Vista.  I couldn't get Fiddler to capture my localhost traffic, even with the period trick on my Vista notebook. Uncheck the IPv6 option in Fiddler and it will work. Below is the link to the site with the answer:

http://groups.msn.com/HTTPFiddler/bugs.msnw?action=get_message&mview=0&ID_Message=815&LastModified=4675632312984197215

January 04

Using Fiddler on localhost


Happy New Year!
 

I've taken a short break from hard-core SharePoint over the holidays and have been experimenting with the Microsoft AJAX Library recently, particularly the Scripting library and Scripting Services - pretty cool stuff.

I had a need to watch some of the traffic from my test page so naturally I turned to Fiddler (www.fiddlertool.com) but noticed it didn't show traffic from the local ASP.NET Development Server on localhost:portnumber.  A quick Google found a couple tips:

  • The most useful for me was to use http://localhost.:portnumber. Notice the period following localhost.
  • You can also use your computer name in place of localhost, but I think this would only work if you were not using the ASP.NET development server and were using IIS directly.
December 16

Updated Best Practice Documents

The documentation on MSDN has been recently updated with some significant new documentation.

http://blogs.msdn.com/sharepointdeveloperdocs/archive/2007/12/11/SharePointSDKsLiveForSP1.aspx

One area with new material is some of the best practices documents, especially dealing with disposing of the Site and Web objects. I discovered I was not handling disposal correctly in one instance that required a page redirection. (Thanks to Andrew Connell for directing me to this http://andrewconnell.com/blog/archive/2007/12/15/Both-SharePoint-v3-WSS-v3-and-MOSS-2007-SDKs-have.aspx)

There have been other areas updated, including some new documentation (finally) on the external storage mechanism (EBS) available in SharePoint. (Which sounds quite challenging to implement successfully)

External Storing of Binary Large Objects (BLOBs) in Windows SharePoint Services
http://msdn2.microsoft.com/en-us/library/bb802976.aspx

November 12

SPQuery with non text fields (Boolean and DateTime)

This isn't anything really new or unique but seemed worth bloging to have it one in place.

If you want to query on a non-text field such as a Yes/No field (boolean) your query CAML might look like the following:

StringBuilder sbQuery = new StringBuilder();
sbQuery.Append(@"<Where>");
sbQuery.Append(@"<Eq><FieldRef Name='" + STR_ISLOGGEDON + @"' /><Value Type='Boolean'>1</Value>");
sbQuery.Append(@"</Eq>");
sbQuery.Append(@"</Where>");
SPQuery query = new SPQuery();
query.Query = sbQuery.ToString();

Note the value for the boolean expressed as text. 1 for true, 0 for false.

I had a need to query on a DateTime field and locate records that had been updated in the last 15 minutes. It appears the query will not operate using the time portion of the DateTime. It only appears to compare the Date portion. I ended up removing the DateTime from the query and checking each row of the result. It turned out to be ok because I had to access each row anyway and either clear a field or perform some process on the row depending on whether the time stamp was inside a 15 minute window.

Here's a link that discusses using DateTime in a CAML query if you go that route:

http://net.bloggix.com/PermaLink,guid,d273feb7-bc14-460d-85e1-863cb6db6016.aspx

October 26

docSTAR Eclipse Released

This has been my daily life for the past 6-9 months or more...  We finally wrapped up and release our first version of docSTAR Eclipse, our newest document imaging/document management offering built upon SharePoint. You can read more about it here:

<commercial>

http://www.docstar.com/docstar/eclipse

eclipse
</commercial>

It has been an interesting ride going from 0-60 on SharePoint about a year ago and then staying in the passing lane with the pedal to the floor. Our small team has learned a lot about SharePoint during that time and I've shared some of the "challenges" here and at local gatherings. Thanks to all who have offered suggestions and encouragement along the way.

FullTextSQLQuery - Keyword search of just documents on one site

I was researching a problem with our search mechanism, which would not return results for certain keywords. It ended up that the number of results being returned for all sites was hitting the RowLimit before the result I wanted appeared. I needed some better filtering. Along the way I discovered a couple tips, one of which appears to be undocumented, to help restrict a search to only documents in a library and only on a given site collection. (I'm also using forms authentication.)

I created the test.aspx page (shown below) to diagnose a search problem and to experiment with search results on a live server without having to build/deploy. Just place it under C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\LAYOUTS (or inside another sub folder.)

Note the IsDocument=1 in the query text. This will restrict this search to only return documents in the results, not the other pages that get indexed, such as: http://xx.xx.xx.xx/My Documents/Forms/DispForm.aspx?ID=29

You can also filter the results to just the site you are currently searching (assuming you want to). If the current user has rights to other sites, those results would be returned as well unless you include the SITE= clause.

SearchTest.aspx:

<%@ Page Language="C#" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="Microsoft.SharePoint.Search" %>
<%@ Import Namespace="Microsoft.SharePoint.Search.Query" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Search" Namespace="Microsoft.SharePoint.Search" Assembly="Microsoft.SharePoint.Search, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="
http://www.w3.org/1999/xhtml" >
<head>
    <title>Search Test</title>
</head>
<body>
<form id="form1" runat="server">
<div>
    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
    <asp:Button ID="Button1" runat="server" Text="Search" />
<%
    if (!HttpContext.Current.User.Identity.IsAuthenticated)
    {
        Response.Write("<br />Please login.<br />");
    }
    else
    {
    if (this.IsPostBack)
    {
        string keywords = this.TextBox1.Text;

        SPSite sitecol = SPContext.Current.Site;
        SPWeb site = SPContext.Current.Web;

        // create a new full text query

        FullTextSqlQuery ftQuery = new FullTextSqlQuery(sitecol);
        ftQuery.QueryText = @"SELECT Path FROM Scope() WHERE FREETEXT(*, '" + keywords + "') AND IsDocument=1 AND SITE='" + site.Url.ToString() + "'"; 

        ftQuery.ResultTypes |= ResultType.RelevantResults;
        ftQuery.Hint = QueryHint.OptimizeWithFullTextIndex;
        ftQuery.KeywordInclusion = KeywordInclusion.AllKeywords;
        ftQuery.SiteContext = new Uri(site.Url.ToString());
        ftQuery.RowLimit = 100;
        ftQuery.TrimDuplicates = true;
        ftQuery.AuthenticationType = QueryAuthenticationType.PluggableAuthenticatedQuery;

        ResultTableCollection resultTables = ftQuery.Execute();
        ResultTable resultTable = resultTables[ResultType.RelevantResults];

        Response.Write("<br />" + "Site Collection: " + sitecol.Url.ToString() + "<br />");
        Response.Write("Site: " + site.Url.ToString() + "<br />");
        Response.Write("Search Keyword: " + keywords + "<br />");
        Response.Write("Search Results:" + "<br />");

   int count = 0;

        while (true == resultTable.Read())
        {
            if (resultTable.FieldCount > 0)
            {
                string columnName = resultTable.GetName(0);
                Object columnValue = resultTable.GetValue(0);

                Response.Write(columnValue.ToString() + "<br />");
                count++;
            }
        }
        Response.Write(count.ToString() + " results.<br />");

    }
    else
    {
        this.TextBox1.Text = "Imported";
    }
    }

 %></div>
</form>
</body>
</html>

The IsDocument=1 tip (which does not appear in the WSS SDK documentation) comes from this question:

http://www.developermania.com/newsgroups/item/316475/FullTextSqlQuery_contains_problem.aspx

I don't recall where I saw the SITE= being used (sorry.)

September 21

WSS 3.0 Search Capabilities - Out of the box

It has been hard to find information that really describes what does and what does not get indexed, for WSS 3.0. I created the following table from experimentation.  The Title and other fields refers to the document name, for example "mydoc.doc", as well as other site columns added to a content type. I didn't test columns added directly to a list, but I'm assuming they would work the same as site columns.

Document Type Extension Title & other fields Indexed File content indexed

Microsoft Word

.doc, .docx Yes Yes
Microsoft Excel .xls, .xlsx Yes Yes
Microsoft PowerPoint

.ppt, .pptx

Yes Yes
Microsoft Output Message .msg Yes No
Text .txt Yes Yes
HTML .html Yes Yes
JPEG (Image) .jpg No No
Bitmap (Image) .bmp No No
TIF (Image)

.tif

Yes No
PDF .pdf No No

The following Wrox book excerpt has some background information regarding search:
http://www.wrox.com/WileyCDA/Section/id-305250.html

This chart refers only to out of the box capabilities. It is possible to install and configure other IFilters, for example to index PDF. For more info on IFilters see www.ifilter.org or www.ifiltershop.com

August 24

Fusion Log Viewer

I came across an interesting utility while trying to debug a custom login page issue today. I am trying to have a custom login page that is used when my site is hit using forms authentication and multiple sites, for example http://vpc1/sites/site1/_layouts/myapp/main.aspx

The web.config in my .../layouts/myapp points to my login page, but it doesn't appear to be used, when I load my I get only the SharePoint login page. At this point I'm thinking something isn't loading in my page, which is failing back to use SharePoint's login page.

The fuslogvw.exe shows the binding work that goes on when IIS loads your page, resolves assemblies, etc. This page has some great information and links:

http://www.developerfusion.co.uk/show/6753/

Here's an example of the log utility in use. It's showing me that SharePoint is loading and using its own login.aspx and not mine:

image

*** Assembly Binder Log Entry  (8/24/2007 @ 9:38:38 AM) ***

The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.

Assembly manager loaded from:  C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
Running under executable  c:\windows\system32\inetsrv\w3wp.exe
--- A detailed error log follows.

=== Pre-bind state information ===
LOG: User = NT AUTHORITY\NETWORK SERVICE
LOG: DisplayName = App_Web_login.aspx.2a428413.ttfbe_56
 (Partial)
LOG: Appbase = file:///C:/Inetpub/wwwroot/wss/VirtualDirectories/80/
LOG: Initial PrivatePath = C:\Inetpub\wwwroot\wss\VirtualDirectories\80\bin
LOG: Dynamic Base = C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\4c47f60c
LOG: Cache Base = C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\4c47f60c
LOG: AppName = 80ee9381
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Inetpub\wwwroot\wss\VirtualDirectories\80\web.config
LOG: Using host configuration file: \\?\C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet.config
LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Temporary ASP.NET Files/root/4c47f60c/80ee9381/App_Web_login.aspx.2a428413.ttfbe_56.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\4c47f60c\80ee9381\App_Web_login.aspx.2a428413.ttfbe_56.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: App_Web_login.aspx.2a428413.ttfbe_56, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
LOG: A partially-specified assembly bind succeeded from the application directory. Need to re-apply policy.
LOG: Using application configuration file: C:\Inetpub\wwwroot\wss\VirtualDirectories\80\web.config
LOG: Using host configuration file: \\?\C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet.config
LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Binding succeeds. Returns assembly from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\4c47f60c\80ee9381\App_Web_login.aspx.2a428413.ttfbe_56.dll.
LOG: Assembly is loaded in default load context.

August 09

List item event handler: ItemDeleted - Is it useless?

I'm not sure what the ItemDeleted event handler is useful for. It doesn't appear that you can get any useful information from the properties object, such as identifying about the item that was deleted. I had a need to perform some cleanup on a separate list when a document was deleted from a library, however I was unable to find any way to identify the document that was just deleted inside this event.

The ListItem property of the properties was null. There is a ListItemID, but this appears to point to the item that was just deleted. In fact, the ListItem property does a GetItemById lookup (under the hood) on the ListItemId. And guess what, the item isn't found because it was deleted.

I wanted to get the ListItem that was deleted, or at least it's UniqueId so I could perform some cleanup but I ended up doing the cleanup in the ItemDeleting event instead. This is potentially problematic because some other handler could be added and it could perform a cancel in the ItemDeleting event, avoiding the deletion on the item.

August 07

Debugging Feature Receiver Event Handler

I've got a feature that installs a couple event handlers on a document library. I'm catching ItemUpdated and added the ItemDeleted. I was trying to use the ListItem property of the properties object, and discovered you can't (see next blog entry). This was rather difficult to debug from inside an event handler. I tried writing to the event log, which worked but was cumbersome. Then I found I could use Trace.Write from the System.Diagnostics namespace and use a separate utility called DebugView to view these trace messages (see link below).

For example:

using System.Diagnostics;

...

Trace.Write("executing at point 1");

I would imagine it is also possible to somehow connect the debugger to the process running the event handler, but the trace command provided the information I needed and allowed me to get it working in short time.

DebugView utility: http://www.microsoft.com/technet/sysinternals/utilities/debugview.mspx

---------------------------------------------------------------------------------------------------------------------------------------------------

Unrelated but interesting:

During the above investigation, I looked at the Sharepoint logs and found this:

An SPRequest object was not disposed before the end of this thread.  To avoid wasting system resources, dispose of this object or its parent (such as an SPSite or SPWeb) as soon as you are done using it.  This object will now be disposed.  Allocation Id: {E954991A-9A53-497E-AD81-5DBB930580EE}  To determine where this object was allocated, create a registry key at HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\HeapSettings.  Then create a new DWORD named SPRequestStackTrace with the value 1 under this key. 

That's interesting, adding a key to the registry can provide more information about where leaks might be coming from. Hmmm...

July 11

Control The Crawl

Here's the answer to something I have been seeking for some time.  How can you trigger a full crawl on the search engine:

Start or stop a full crawl

To start a full crawl of the content, use the following syntax:

Stsadm -o spsearch -action fullcrawlstart

To stop a full crawl of the content, use the following syntax:

Stsadm -o spsearch -action fullcrawlstop

This is from the technet docs

http://technet2.microsoft.com/windowsserver/WSS/en/library/bc15d0a8-b48f-4d32-a267-797f8515d1f31033.mspx?mfr=true

July 03

Best Practices Follow-up

Here's a page with a good explanation of the need to dispose your site and web objects (when you open them) and a demonstration of the effects of not following this pattern.

http://blogs.msdn.com/jannemattila/archive/2007/06/29/free-the-spweb.aspx