Tuesday, 18 November 2008

Getting Mirrored Blog Items to show in a AggregatePostList control : Community Server 2.1 SP3

The control declaration:

<Blog:AggregatePostList
                runat="Server"
                PageSize="5"
                id="AggregatePostList1"
                IncludeAutodiscovery="true"
                IncludeCategories="true"
                ScorePosts="true"
                ApplicationKey="News"
                MirrorDisplayType="AllBlogs"
                EnablePaging="false"
                EnableTitle="false">
              <SkinTemplate>
                <h2 class="CommonTitle">
                  <asp:Literal runat="server" id="title" Visible="false" />
                  News
                </h2>
                <Blog:AggregateList id="Posts" runat="Server" EnableTitle="false"/>
              </SkinTemplate>
            </Blog:AggregatePostList>

NOTE: ApplicationKey needs to be set to the blog name.  Each mirrored blog needs the "Aggregate in site blog roll" checkbox checked so that it appears in the aggregate control, as above.  Changing this flag after the blogs have been mirrored will not make a difference, retrospectively.

To configure existent posts to appear in the Community Aggregate, just run

update cs_posts
set PostConfiguration = 55 where SectionID = XXXX

Where the section id is the id of the blog. Look in select * from cs_sections where name = 'blog name' for the section id.

Invoke the CS 2.1 RollerBlogUpdater manually

CommunityServer.RollerBlogs.Components.RollerBlogUpdater r = new CommunityServer.RollerBlogs.Components.RollerBlogUpdater();
        r.Execute(CommunityServer.Configuration.CSConfiguration.GetConfig().GetConfigSection("CommunityServer/Jobs").ChildNodes[17]);

Where 17 in the index of the job node in the Jobs section of CommunityServer.config

Community Server 2.1 SP3 : Blogs :: Mirrored Feeds

If mirrored feeds do not work correctly, it's because the "RollerBlogUpdater" job inside Community Server runs under the "Anonymous User" context.  Ensure the blog in question has VIEW permissions on the Everyone role (the Everyone role is the only role that the Anon user is associated with)

Thursday, 4 September 2008

Migrating ASP.NET apps to Windows Server 2008 / IIS7 - URLs with '+' don't work

Having successfully migrated production .NET v3.5 web applications over to Server 2008, one issue is that some URLs don't work, ie. ones that have a '+'.  This is because IIS7 rejects such URLs with Error 404.11 'URL_DOUBLE_ESCAPED'; See here.

To resolve it, simply put

<system.webServer>
  <security>
    <requestFiltering allowDoubleEscaping="false" />
  </security>
</system.webServer>

...in your web.config under 'configuration'

This makes the server less secure against Canonicalization Attacks.

Thursday, 28 August 2008

LINQ-To-SQL auto-generate failure. "The custom tool 'MSLinqToSQLGenerator' failed. Unspecified error." Visual Studio 2008 SP1 bug. SourceSafe may delete your designer.cs file!

If you have a partial class associated with a LINQ DataContext DBML's designer.cs file, then after Visual Studio 2008 SP1 is applied, the designer file may not be created properly IF you have a using statement declared outside of the namespace.

The simple solution is to move the using statements inside the namespace construct.

A bug has been posted to Microsoft.  I'm just glad it's a simple solution.

thanks, k

Wednesday, 27 August 2008

Unable to dismiss ModalPopupExtender dialog with CancelControlId or behaviour's hide method

This is because the TargetControlId must not be the panel.  I found that if I created a HiddenField control, just inside the popup panel, this makes the Cancel and OK buttons work as expected.

Thursday, 21 August 2008

Community Server 2.1 SP3 with IIS 7 : "Request is not available in this context"

Unfortunately, CS 2.1 will not work out-of-the-box with IIS 7.0.  There is a small problem where the Job initialisation routine attempts to get the Application's Path  on application start-up from the current request - i.e. the request that started the application.  This will no longer work because the request has been decoupled from application start-up.

This is a simple change though... just change the ApplicationPath property getter inside Globals.cs to

static public string ApplicationPath {

            get {
                string applicationPath = "/";
                if(HttpContext.Current != null)
                    applicationPath = HttpRuntime.AppDomainAppVirtualPath;

                // Are we in an application?
                //
                if (applicationPath == "/") {
                    return string.Empty;
                } else {
                    return applicationPath;
                }
            }

        }

 

The change is simple to get the Application Path from the Http Runtime, rather than the request object. i.e. using AppDomainAppVirtualPath

Just re-compile in release mode and you're away.  Also, ensure the SP level of your CS source code is the same as the binary in your app.

Here are the version numbers and release dates for CS 2.1

  • CS 2.1 Build 2.1.60809.935 August 9, 2006             RTM
  • CS 2.1 Service Pack 1 Build 2.1.61025.2 October 30, 2006
  • CS 2.1 Service Pack 2 Build 2.1.61129.2 December 5, 2006
  • CS 2.1 Service Pack 3 Build 2.1.20416.3 April 16, 2007

thanks

k

Wednesday, 6 August 2008

Backing Up Visual SourceSafe with a batch script, WinZip and FTP

Obviously source code is the most important thing to any software project and I wanted to make sure that we had automated process in-place which would ensure we had an archive of weekly, off-site backups of our work. 

So I assembled a batch script like this:

@For /F "tokens=1,2,3 delims=/ " %%A in ('Date /t') do @(
    Set Month=%%B
    Set Day=%%A
    Set Year=%%C
)
@set filename=VSS%Year%%Month%%Day%bak.zip
echo Creating %filename%...
"C:\Program Files\WinZip\wzzip.exe" -p -r "C:\VSS_BACKUP_ZIPS\%filename%" "c:\VSS_BACKUP\*.*"
echo Done

REM --- CREATED ZIP ---

set FTPADDRESS=127.0.0.1
set SITEBACKUPFILE=%filename%

REM set /p FTPUSERNAME=Enter FTP User Name:
REM set /p FTPPASSWORD=Enter FTP Password:

set FTPUSERNAME=myusername
set FTPPASSWORD=mypassword

CLS
> script.ftp USER
>>script.ftp ECHO %FTPUSERNAME%
>>script.ftp ECHO %FTPPASSWORD%
>>script.ftp ECHO binary
>>script.ftp ECHO prompt n
:: Use put instead of get to upload the file
>>script.ftp ECHO CD VSSBackups
>>script.ftp ECHO put %SITEBACKUPFILE%
>>script.ftp ECHO bye
FTP -v -s:script.ftp %FTPADDRESS%
TYPE NUL >script.ftp
DEL script.ftp

This script depends on the following:

  • Visual SourceSafe is configured to maintain a Shadow directory, which contains all the latest files.
  • WinZip and the WinZip Command Line Add-on (although I'm sure this can easily be replaced by something free)
  • Microsoft's FTP.exe program in Windows\System32.

It does the following:-

  1. It parses out the various components of the current date into variables: month, day and year. 
  2. Creates the zip of the VSS shadow folder, with a filename containing today's date in the format 'yyyyMMdd'
  3. Generates a temporary FTP command file called 'script.ftp'.  This commands the FTP program to upload the zip file.
  4. Invokes FTP.exe to process the command file, thus uploads the zip off-site.

 

Once I'd tested it, I used the Windows Task Scheduler to invoke it every Sunday night at 1am.

Now we have peace of mind.

thanks

Kris

Wednesday, 9 July 2008

Simply query an XML column in SQL Server 2005

Imagine you wanted to just capture a context dump of everything, every time an exception is raised...

Imagine that you did, in fact, create an XML context dump...

Imagine this XML looks a bit like this...

<ContextData>
<Section Name="Exception Report">
<Section Name="Request Information">
<NVP N="Date &amp; Time" V="Friday, July 04, 2008 1:09:26 PM" />
<NVP N="Url" V="https://url" />
<NVP N="Query" V="querystring" />
<NVP N="Current User" V="Kristan Dyson" />
<NVP N="Browser" V="AppleMAC-Safari" />
<NVP N="User Agent" V="Mozilla/5.0 (Macintosh; blah)" />
<NVP N="IP Address" V="" />
<NVP N="Url Referrer" V="https://url" />
</Section>


</ContextData> 



Now imagine you stored that in a database table called 'Exception' with the schema...




id    int
ContextData xml
Date datetime
Message nvarchar
GUID uniqueidentifier




and you wanted to find all exceptions that a particular user had experienced... you can use xpath in the where clause




SELECT  guid,message, ContextData


from Exception 


where date > '20080701'


and ContextData.exist('(/ContextData/Section[@Name="Exception Report"]/Section[@Name="Request Information"]/NVP[@V="username"])') = 1




This queries the XML data and returns rows like



111D0332-7F95-4929-A129-79715974BB38    Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.



This is just a user support scenario I had to cover.

Friday, 4 July 2008

Note to Self

In LINQ to SQL, If SubmitChanges() on the DataContext doesn't do anything having just updated a row, remember to ensure the Primary key is set on the table in the schema.

Wednesday, 18 June 2008

UK Postcode Regular Expression

Very useful: ^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$

REF: http://regexlib.com/REDetails.aspx?regexp_id=260

Monday, 9 June 2008

Build (web): Object '[...].rem' has been disconnected or does not exist at the server

We had this constantly during a build (during the validation part) of a web application in Visual Studio 2008.  I think it occurred just after the machine name changed, but cannot be sure.

We also got the error 'The application domain in which the thread was running has been unloaded'; but only once.

We opened a Microsoft Support case for it - they managed to suppress the error by putting the following in the web.config

<system.codedom>

<compilers>

<compiler language="c#"

type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" extension=".cs" compilerOptions="/nostdlib /d:DEBUG;TRACE /warnaserror-" warningLevel="0"/>

<!-- /nowarn:0162,0108,0114,0252 -->

</compilers>

</system.codedom>

Under "configuration".

We're still waiting on a response from MS Support and we believe it's an MS bug.  At least with the above, it's possible to get on with the job!

Kris

UPDATE: 25TH JUNE 08:

OK, this bug has been sent via Redmond and I had a response today: "As a follow up to your question below… We investigated this area and it came out to be a known bug which we are fixing in SP1 version of ASP.NET…  So do ask Kristan to look forward to it".

Visual SourceSafe Internet

Over the weekend I tried to get Visual SourceSafe Internet working so that i could work remotely on projects via HTTPS.

My server is Windows Server 2003 with IIS 6.0 and VSS is v. 2005 (incidentally there is a service pack available for VSS 2005, although they've called it a GDR [general distribution release] and it's available here)

Normally you should be able to use the VSS Admin tool's "Configure" option to publish the database on the Internet.

Unfortunately, I spent 5 hours trying to get this to work.  I got so far as enabling SSL, remotely browsing to the correct VSS project in the project tree and doing a Get Latest, but whenever I checked anything in I would get "There was a failure uploading the URL" etc; "Do you want to retry the operation?"

I used Fiddler to try to debug what was actually happening, and it translated as a "403.3 Forbidden" from IIS.  This would normally mean that write access is denied, but the application pool identity and the IIS anonymous authentication identity both had full access to the VSS temp upload directory.

The check-in mechanism of VSS Internet appears to use WebDAV underneath; so you need to ensure the WebDAV extension is enabled on the web server in the IIS Admin tool.  Also, need to ensure that the PUT HTTP verb is accepted.  If URLScan is installed (this seems to help lockdown the http verbs that iis can accept) then you need to ensure the PUT verb is inside the AllowedVerbs section of the urlscan.ini (system32\inetsrv\urlscan).

All this, plus, giving the Everyone user full read/write privileges to the VSS upload dir, did not work.

Write Access is Denied.

hmmmm as a last resort, I downloaded the IIS metabase explorer (in the IIS 6.0 resource kit) and changed the id from the website from 2350, to 1; and changed the one that was "1" to "2351"!  I did this because the VSS Admin tool tries to enable the database on the website with the ID of "1".   I then deleted any virtual directories in any Web Applications/Websites called "SourceSafe". 

Then I tried the VSS Admin tool.  It interacted with the correct website.  This seemed to work.  Whatever magic the VSS Admin tool weaves - it worked - provided that the website id of the website that you wish to enable  source control on is "1".

I can honestly say, I have no idea what was really wrong, however, my experience has been:

  • VSS is generally a poor product at the best of times
  • WebDAV is equally dodgy.  It seems the IIS team don't talk with the WebDAV team.

It's also my view, that MS should have tested this a hell of a lot more... the problems are prominent and totally reproducible!

So the motto of this story is; get the VSS Admin tool to set up the Internet database access, but make sure that the metabase id of the website is 1 beforehand.  I think you can then change it back if you want, although i haven't done this.

Once VSS Internet is configured, it seems to work OK.  If you're using Windows Vista and VSS 2005, make sure you install the GDR ("service pack") so that the VSS UI works properly inside Visual Studio 2008.

For general guidance, see this.

Kris

SQL Server Edition

SELECT @@VERSION
will do the job

Friday, 25 April 2008

.NET Settings, Settings and more Settings (the configSource and File Attribute)

well, today for the first time I thought I would tackle the problem we have in managing the settings of our .NET applications. It's friday so I thought I'd celebrate with this.
Anyway, so we have loads and loads of settings for our applications some are:
  • specific to the application
  • specific to the configuration/environment
  • generic to all of the applications

Most of our applications are ASP.NET 2.0 web apps, and therefore we had previously stored our settings data inside web.config under the node.

Then last year we need to split out the settings on a per-configuration / environment basis, so we created a /_config/ directory in the root of our web app.

In this we placed

  • /dev,
  • /prod and
  • /staging.

The principle is simple: just create appSettings.config and place it inside /dev, then reference it from web.config with the "file" attribute of the appSettings node; e.g. web.config ->

The file attribute will mean the contents of the specified file will override and merge with nodes directly underneith the inline node. This is cool. Because you can specify environment-agnostic settings inside the inline section of web.config, and then they will either be overriden by nodes with the same name inside the dev\appSettings.config file.

Great... kinda.

But the problem is, we actually don't want to maintain settings that are shared amongst different applications inside web.config. This is because if one setting needs to change, you need to specify the change throughout all web.configs of all applications.

We can't "share" the web.config amongst all applications, as each app needs different web.config sections / settings for other stuff. Also, we can't share a section of web.config.

So how can we find a neat solution to just:

  • Store and share settings that are agnostic to the application, the environment in which the application is deployed and are essentially global to a company's apps.
  • And also, specify settings that are the opposite: i.e. settings that are specific to the app and the environment.

I had tried using a heirarchy of file attributed nodes, i.e. in web.config specify a file containing the agnostic app settings and the specify a file inside that for app/env-specific settings... but .NET doesn't support merging down more than 1 level.

The Use Of The File Attribute and Config Source Attribute
arrrrh! that's the one.

So the solution is to put inside web.config:

[no inline nodes allowed]

Inside GenericAppSettings.config put:

Then create dev\appSettings.config



In our source control management system (VSS), we then share GenericAppSettings.config, amonst all of our apps and now we can rest assured that nothing will be left as obselete or broken. i.e. Generic settings can now be updated once for the whole enterprise.

so there you go another great solution for configuration management!

Kris

Thursday, 24 April 2008

Wednesday, 23 April 2008

Me


Drinking again