SharePoint 2007 ONET.xml AlternateHeader
0 CommentsPublished by Ciaran McAuliffe on Monday, October 16, 2006 at 7:20 AM.
This is true for SharePoint 2007 B2 TR1:
Even though AlternateHeader does not show up in the schema for ONET.xml, you can still use it in the same way you would in SharePoint 2003. The only difference this time is that MS has bundled the alternate header logic into a control (see below). As far as I can see this control is only present on pages that use the application.master i.e. any pages that live under /_layouts/..., so you will have to add it to your master pages to get a consistant look around your site.
<%@ Register TagPrefix="wssuc" TagName="TopNavBar" src="~/_controltemplates/TopNavBar.ascx" %>
Moss 2007: File Not Found error on Login.aspx page when using anonymous access
0 CommentsPublished by Ciaran McAuliffe on Tuesday, October 10, 2006 at 11:44 AM.
This post saved my sanity, hopefully it will save yours. If you have experienced the File Not Found error on the Login.aspx page when using anonymous access this will solve your problem.
http://www.infusionblogs.com/blogs/kguenther/archive/2006/06/27/608.aspx
Using the ASP.NET Web Site Administration Tool with IIS
7 CommentsPublished by Ciaran McAuliffe on Sunday, October 8, 2006 at 9:16 PM.
On this Canadian Thankgiving weekend my thoughts take me through the year gone by, and I wonder...Where did my "The Internet Is Awesome!" t-shirt go?...Why am I still waiting for the final installment of the Seinfeld DVDs to be released?...and Why the hell can I not get the ASP.NET Web Site Administration Tool to work on any IIS web site except for the Default Web Site?
This is a question one hell of a lot of people have been asking, anyone who tries to do this on any site except for the Default Web Site ends up with the following error:
An error was encountered. Please return to the previous page and try again.
The following message may help in diagnosing the problem:
IInternalConfigConfigurationFactory.Create(Type typeConfigHost, Object[] hostInitConfigurationParams) at System.Web.Configuration.WebConfigurationHost.OpenConfiguration(WebLevel webLevel, ConfigurationFileMap fileMap, VirtualPath path, String site, String locationSubPath, String server, String userName, String password, IntPtr tokenHandle) at System.Web.Configuration.WebConfigurationManager.OpenWebConfigurationImpl(WebLevel webLevel, ConfigurationFileMap fileMap, String path, String site, String locationSubPath, String server, String userName, String password, IntPtr userToken) at System.Web.Configuration.WebConfigurationManager.OpenMappedWebConfiguration(WebConfigurationFileMap fileMap, String path) at System.Web.Administration.WebAdminPage.OpenWebConfiguration(String path, String appPhysPath, Boolean getWebConfigForSubDir) at System.Web.Administration.WebAdminPage.OpenWebConfiguration(String path, Boolean getWebConfigForSubDir) at System.Web.Administration.WebAdminPage.VerifyAppValid()
Isn't that pretty!
It would seem that MS only wants this site to work with Cassini, i.e. the web server that comes with Visual Studio 2005. Well it is a great site, and it saves you so much work, so I wanted to include it in a project I am working on, so I set out this morning determined to figure out the problem and get it working, and I did.
The web site itself lives in C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ASP.NETWebAdminFiles\App_Code, and if you look inside the App_Code folder you will find the code behind class for the default.aspx page, it is called WebAdminPage.cs. If you have a look inside this class, at around line 328, you will find a function called OpenWebConfiguration:
private Configuration OpenWebConfiguration(string path, string appPhysPath,
bool getWebConfigForSubDir) {
// check if session expired
if (String.IsNullOrEmpty(ApplicationPath) ||
String.IsNullOrEmpty((string)Session[APP_PHYSICAL_PATH])) {
Server.Transfer("~/home2.aspx");
}
if (String.IsNullOrEmpty(path)) {
return WebConfigurationManager.OpenWebConfiguration(null);
}
string appVPath = (string)Session[APP_PATH];
if (!getWebConfigForSubDir) {
appVPath = path;
}
WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
fileMap.VirtualDirectories.Add(appVPath, new VirtualDirectoryMapping(appPhysPath, true));
return WebConfigurationManager.OpenMappedWebConfiguration(fileMap, path);
}
The problem occurs in the WebConfigurationManager.OpenMappedWebConfiguration(fileMap, path); function. The WebConfigurationManager class lives inside the System.Web dll, inside the System.Web.Configuration namespace. The OpenMappedWebConfiguration function has three alternates, the first one we have already seen, the third one we are not internested in, and the second one will help us solve our problem.
public static System.Configuration.Configuration OpenMappedWebConfiguration
(WebConfigurationFileMap fileMap, string path, string site)
{
return WebConfigurationManager.OpenWebConfigurationImpl(WebLevel.Path, fileMap, path, site, null,
null, null, null, IntPtr.Zero);
}
You can see the this version of the OpenMappedWebConfiguration function takes an extra parameter called site, and this corrisponds to the name of the IIS website which the call came from. The solution to our problem is this...when this web site is being used by IIS we need to use the second version of the OpenWebConfigurationImpl and pass it the name of the current IIS website, if we are not using IIS then we just use the first version of OpenWebConfigurationImpl.
So why will this website work on the Default Web Site in IIS, without any modifications, I really don't know. I used Reflector and found that the errors were coming from the three functions below, which can be found in the System.Configuration dll, in the System.Configuration namespace, in the Configuration class, the problem is around IsVirtualPathConfigPath returning false, I would guess, but unfortunatly, there is no real way to debug this.
public override void InitForConfiguration(ref string locationSubPath, out string configPath,So, here is the solution to our problem:
out string locationConfigPath,
IInternalConfigRoot configRoot,
params object[] hostInitConfigurationParams)
{
WebLevel level1 = (WebLevel) hostInitConfigurationParams[0];
ConfigurationFileMap map1 = (ConfigurationFileMap) hostInitConfigurationParams[1];
VirtualPath path1 = VirtualPath.CreateAbsoluteAllowNull((string) hostInitConfigurationParams[2]);
string text1 = (string) hostInitConfigurationParams[3];
if (locationSubPath == null)
{
locationSubPath = (string) hostInitConfigurationParams[4];
}
base.Host.Init(configRoot, hostInitConfigurationParams);
this.SetConfigRoot(configRoot);
this.ChooseAndInitConfigMapPath(false, null, map1);
WebConfigurationHost.GetConfigPaths(this._configMapPath, level1, path1, text1,
locationSubPath, out this._appPath,
out this._appSiteName, out this._appSiteID,
out configPath, out locationConfigPath);
this._appConfigPath
= WebConfigurationHost.GetConfigPathFromSiteIDAndVPath(this._appSiteID, this._appPath);
if (WebConfigurationHost.IsVirtualPathConfigPath(configPath))
{
string text2;
VirtualPath path2;
WebConfigurationHost.GetSiteIDAndVPathFromConfigPath(configPath, out text2, out path2);
string text3 = this._configMapPath.MapPath(text2, path2);
if (string.IsNullOrEmpty(text3))
{
throw new ArgumentOutOfRangeException("site");
}
}
}
internal static void GetSiteIDAndVPathFromConfigPath(string configPath, out string siteID,
out VirtualPath vpath)
{
if (!WebConfigurationHost.IsVirtualPathConfigPath(configPath))
{
siteID = null;
vpath = null;
}
else
{
int num3;
int num1 = "MACHINE/WEBROOT".Length + 1;
int num2 = configPath.IndexOf('/', num1);
if (num2 == -1)
{
num3 = configPath.Length - num1;
}
else
{
num3 = num2 - num1;
}
siteID = configPath.Substring(num1, num3);
if (num2 == -1)
{
vpath = VirtualPath.RootVirtualPath;
}
else
{
vpath = VirtualPath.CreateAbsolute(configPath.Substring(num2));
}
}
}
internal static bool IsVirtualPathConfigPath(string configPath)
{
return (configPath.Length > "MACHINE/WEBROOT".Length);
}
- Backup the WebAdminPage.cs i.e. Copy and past the WebAdminPage.cs class and rename it to WebAdminPage.cs_old
- Add the following function somewhere into the WebAdminPage class:
///
/// Checks to see if the request has come in through an IIS web server
///(i.e. not Cassini), and
/// if so, gets the IIS website instance and returns it's name
///
/// The incoming request
///The name of the iis website through which the call has come in from.
///If this is anything other
/// than an IIS website and empty string will be returned.
private string GetSiteName(HttpRequest request)
{
///the server variables key for iis instance id
const string instanceIdKey = "INSTANCE_ID";
///the server variable key for the type of server the call came from
const string serverSoftwareKey = "SERVER_SOFTWARE";
///the iis properties key for the name of the website in IIS
const string serverCommentKey = "ServerComment";
///the name of the IIS server w/o version
const string iisServerName = "Microsoft-IIS";
///the base path name of the website in iis w/o its instance id
const string iisPathBase = "IIS://localhost/W3SVC/";
///get the instance id of the iis website that the call came from
string instanceId = request.ServerVariables[instanceIdKey];
///get the type of web server that the call has come from
string webServer = request.ServerVariables[serverSoftwareKey];
///we only want to perform these operations if this is an IIS website
if (webServer.ToLower().IndexOf(iisServerName.ToLower()) > -1)
{
///get the iis website
System.DirectoryServices.DirectoryEntry webSiteDir =
new System.DirectoryServices.DirectoryEntry(iisPathBase + instanceId);
///get the property which contains its name
return (string)webSiteDir.Properties[serverCommentKey].Value;
}
else
return string.Empty;
} - Alter the
private Configuration OpenWebConfiguration(string path,
function to look like this:
string appPhysPath,
bool getWebConfigForSubDir)private Configuration OpenWebConfiguration(string path, string appPhysPath,
bool getWebConfigForSubDir) {
// check if session expired
if (String.IsNullOrEmpty(ApplicationPath) ||
String.IsNullOrEmpty((string)Session[APP_PHYSICAL_PATH])) {
Server.Transfer("~/home2.aspx");
}
if (String.IsNullOrEmpty(path)) {
return WebConfigurationManager.OpenWebConfiguration(null);
}
string appVPath = (string)Session[APP_PATH];
if (!getWebConfigForSubDir) {
appVPath = path;
}
WebConfigurationFileMap fileMap = new WebConfigurationFileMap();
fileMap.VirtualDirectories.Add(appVPath,
new VirtualDirectoryMapping(appPhysPath, true));
///get the name of the website, this will only have a value if we are using IIS
string siteName = GetSiteName(Context.Request);
///if it is null or empty we are not using IIS, so we do not
///need to supply the site name
if(string.IsNullOrEmpty(siteName))
return WebConfigurationManager.OpenMappedWebConfiguration(fileMap, path);
else
return WebConfigurationManager.OpenMappedWebConfiguration(fileMap, path, siteName);
} - Finally add the following code the the web.config file in C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ASP.NETWebAdminFiles inside the System.Web tag
<compilation>
<assemblies>
<add assembly="System.DirectoryServices, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=B03F5F7F11D50A3A"/>
assemblies>
compilation>
Now you can just create your website in IIS, create a virtual directory and point it to C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ASP.NETWebAdminFiles, here is how do do that:
- Create a website in IIS
- Make sure it is set to run using ASP.NET 2.0
- Create a new virtual directory called ASP.NETWebAdminFiles and point it to C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ASP.NETWebAdminFiles.
- Right click on the Virtual Directory and select Properties
- Click on the Virtual Directory tab and click the Create button beside Application Name.
- Change Execute Permissions to Scripts Only.
- Click on the Directory Security tab, click on Edit button for, Authentication and access control.
- Unclick Enable anonymous access and make sure Integrated Windows Authentication is the only check box clicked under Authenticated Access
- You can now go to the site using the following url as a template http://localhost:8081/asp.netwebadminfiles/default.aspx?applicationPhysicalPath=C:\Documents%20and%20Settings\Administrator\My%20Documents\Visual%20Studio%202005\WebSites\WebSite1\&applicationUrl=/WebSite1
- You may have to set read/write permissions on the Web.config of the web site that are trying to control the security for, as the ASP.NET admin site will try to edit it.
I hope this helps out a few people, please let me know if I need to make some corrections on this.
Thanks.