April 2005 - Posts

Today another interesting article about BizTalk is published, it seems that today is BizTalk-day! During my BizTalk courses a lot of people ask questions about the performance of a BizTalk server. I always try to let them think about it themselves because performance is dependent on a lot of things (both internal and external), there is no default answer. So if you want to have some facts and figures and some optimization guidelines, go and read the article. Also recommended!

BizTalk Server 2004 Performance Characteristics

This document provides information about the performance of Microsoft BizTalk Server 2004. The BizTalk Server product team derived the performance characterization from thousands of test cases that isolated and measured the performance of individual configurations and components of BizTalk Server 2004. This document presents the results of this testing and explains some of the significant findings. It does not provide any specific instructions about optimizing a particular BizTalk Server 2004 deployment.

There's a very good article and extensive (88 pages!) on MSDN that covers a lot of the problems and issues that you will encounter when you are developing using BizTalk Server 2004. A must-read for anyone who is working with BizTalk! Some of the discussed topics:

  • MSF and BizTalk development
  • Team development
  • Organizing VS.NET projects and solutions
  • Naming guidelines
  • HAT
  • Debugging and trouble-shooting
  • Deployment
Developing Integration Solutions with BizTalk Server 2004

This guide contains examples of team approaches for developing with BizTalk Server 2004, and illustrates techniques that can increase development efficiency. It also provides hints and tips that can decrease the time and effort spent debugging and testing. It emphasizes the team development process and team development setup.

This guide focuses on projects that use the core messaging and orchestration functionality of BizTalk Server. It does not cover in detail additional areas such as Business Activity Services (BAS), Business Activity Monitoring (BAM), Human Workflow Services (HWS), XREF, or the Business Rules Engine (BRE).

Some time ago Patrick, Karine and myself were brainstorming on what cool tools we could create for SharePoint. One of the things was to create a VS.NET extension like the Server Explorer, or the BizTalk Explorer. We never started developing it, but luckily Ciaran had the same idea and did started a similar project on GotDotNet: SharePoint Explorer. I haven’t got the time to check it out, but it sounds promising: (extract from an email he sent me) “The developer will be able to browse the whole portal through a tree structure, similar to windows explorer, and view web-parts, properties, etc. on each site along the way, and then at any point the developer could right click on a site or web part and be able to view it in the VStudio browser or IE. There would also be a limited amount of administrative tasks the developer could perform, tasks like creating/deleting sites, security, and others that can be decided as the project is planned.  I have already created a basic sample of this and I have uploaded the source into the source control of the workspace, you can also see some screen shots that I have made available from a link in the top news item on the front page.”

That are already some nice features, here’s another one: generate code based on the item selected in the explorer. For example right clicking on a specific List or Document Library, would generate some code that would give you an instance of that List or Document Library. You can even stretch that idea and think about integrating our U2U CAML Query Builder Tool. Anyone else has some feature requests, and/or some free time to contribute to the project?

There's a new version of my favorite RSS reader available: RSS Bandit v1.3.0.29. One of the reasons why I like RSS Bandit (besides that it's free) is that it supports authentication. Why would you use authentication on a RSS feed? Well suppose you have your SharePoint sites extended with RSS feeds (using the U2U RSS Feeds for SharePoint) and you have some feeds that are not available to anonymous users. That's when you can use RSS Bandit to access them, using your own Windows user account.

So what's new in this version? I really like the newspaper view and the UI improvements in general. Nice job Dare and the rest of the team!

Just like Patrick I'm having a pretty densed travelling schedule the last few weeks. This week I was in Saudi Arabia, teaching a BizTalk course. This is really an amazing country, if you ever have a chance to visit it ... Some of my students gave me a personal sight seeing tour in the city of Jeddah: impressive. Thanks guys!

I haven't been able to keep up with all my blog subscriptions, but there's one that's really worth mentioning (probably you've already heard about it): Michael's Greth first SharePoint Podcast in English.Nice work Michael! I now that Patrick is really looking forward to something like that as well, he's even advertising his appearance on the SharePoint Advisor Conference in the podcast. So maybe you'll hear about a U2U SharePoint Podcast later on, or should we join Michael?

I'm off to the airport to fly home! By the way if you're in Zurich next week and if you want to have a geek-drink, drop me a line!

Today I got the excellent news that I am now MVP for SharePoint Portal Server, just like my pal Patrick! I would like to thank the SharePoint community and everybody who made this possible. Especially U2U for giving me the opportunities to accomplish this.

Last week I did some SharePoint consultancy for a Belgian University (LUC), where they had an interesting issue with SharePoint Portal Server areas. Each research group in the university has it's own WSS site(s) in which they work on documents. Once such a document is finished, the document is published to an SPS area. Ok nothing special you may think, but the tricky part is that only selected people have read access to the WSS site where the actual document is located. Remember that when you publish a document to a SPS area, only a link will appear in the area pointing to the corresponding site. So if a user which doesn't have read rights on the WSS site visits the area, he will see a link to the document. But if he clicks that link, he will get the famous login popup because he cannot access the document! So how do you solve this issue without having to replicate data?

 

I came up with following solution: impersonating another user to get the document from the WSS site, and passing the document back to the user who requested it in the first place. Of course the process should be transparent for the users. So far the theory, let's take a look at the technical implementation. Because I really like creating web parts, I've put everything inside one web part, built using the SmartPart of course. The web part's first job is to provide an alternative display to display the items that are published to an area. The intresting part here is to figure out which area the web part is located on:

// Get current area 
SPWeb currentWeb = SPControl.GetContextWeb(this.Context);
Area currentArea = AreaManager.GetArea(PortalContext.Current, currentWeb.ID);

Once you've got a hold of the area instance, you can use the Listings property to loop over all the published items:

string html = ""; 
foreach(AreaListing al in currentArea.Listings)
{
if(al.Status == ListingStatus.Approved)
{
html += string.Format("<a href='{0}'>{1}</a><br>" , this.Request.Url + "?url=" + al.URL ,al.Title);
}
}
Literal1.Text = html;

The code above displays all the items in pretty ugly, but simple, way (a string containing html put in a literal control). I leave it up to your imagination to figure out a nicer way. Notice that the destination of the link is the current page's url, with an url property added to the query string.

The second part of the web part is to do the impersonation magic to get the file which s url is specified in the query string. I've used a WebClient object to accomplish this, you can use it to easily impersonate a specific account and get the binary data of the document:

System.Net.WebClient wc = new System.Net.WebClient(); 
wc.Credentials = new System.Net.NetworkCredential("administrator", "secret");
Byte[] bytes = wc.DownloadData(Request.QueryString["url"]);

Once you get the binary data, you can send it to the Response object using the BinaryWrite method. Before that, you need to add some headers to the Response so the web browser will notice that binary data is sent. The code below will copy all the headers from the WebClient to the Response. At the end the Content-Disposition header is added, so the document will open outside the browser. If you omit this last header, the document will be shown inside the active browser instance.

foreach(string headerKey in wc.ResponseHeaders.Keys) 
Response.AppendHeader(headerKey, wc.ResponseHeaders[headerKey]);
Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName);
Response.BinaryWrite(bytes);

If you put both parts together you get following code in the PageLoad event of the Web User Control (remember that I'm using the SmartPart). If you're interested in the complete solution let me know, if there's enough interest, I'll clean up the code some more and publish this web part.

private void Page_Load(object sender, System.EventArgs e) 
{
if(Request.QueryString["url"] == "" || Request.QueryString["url"] == null)
{
// Get current area
SPWeb currentWeb = SPControl.GetContextWeb(this.Context);
Area currentArea = AreaManager.GetArea(PortalContext.Current, currentWeb.ID);
string html = "";
foreach(AreaListing al in currentArea.Listings)
{
if(al.Status == ListingStatus.Approved)
{
html += string.Format("<a href='{0}'>{1}</a><br>" , this.Request.Url + "?url=" + al.URL ,al.Title);
}
}
Literal1.Text = html;
}
else
{
Response.Clear();
System.Net.WebClient wc = new System.Net.WebClient();
wc.Credentials = new System.Net.NetworkCredential("administrator", "secret");
Byte[] bytes = wc.DownloadData(Request.QueryString["url"]);
string[] urlParts = Request.QueryString["url"].Split(char.Parse("/"));
string fileName = urlParts[urlParts.Length - 1];
foreach(string headerKey in wc.ResponseHeaders.Keys)
Response.AppendHeader(headerKey, wc.ResponseHeaders[headerKey]);
Response.AppendHeader("Content-Disposition", "attachment;filename=" + fileName);
Response.BinaryWrite(bytes); Response.End();
}
}
More Posts