InfiniTec - Henning Krauses Blog

Don't adjust your mind - it's reality that is malfunctioning

Using the GenuineChannels SharedMemory Channel with Windows Vista

If you are using the shared memory remoting channel from GenuineChannels under Vista, you can quickly become a victim of a new security feature of Windows Vista: Global objects (a Mutex in the global namespace, for example) can only be created in session 0 - and with Vista, only services run in session 0.

The GenuineChannels SharedMemoryChannel creates a global mutex by default, and will fail with with this error message:

Can not create or open a memory file mapping. Error code: 2. Use the Visual C++ Error Lookup utility to see the text of the error message.

Consider the following code for the initialization of the remoting infrastructure:

    1 publicvoid InitializeRemoting(string name, string address)

    2 {

    3     Hashtable properties;

    4     GenuineSharedMemoryChannel channel;

    5 

    6     properties = newHashtable();

    7 

    8     properties = newHashtable();

    9     properties["listen"] = address;

   10     properties["name"] = name;

   11     properties["priority"] = 100;

   12 

   13     channel = newGenuineSharedMemoryChannel(properties, null, null)

   14     ChannelServices.RegisterChannel(channel);

   15 }

To force the channel to create session-local objects only, insert the following line at line 12:

   12     properties["smsessionlocal"] = true;

 


Technorati:

Posted by Henning Krause on Wednesday, November 1, 2006 12:00 AM, last modified on Wednesday, November 1, 2006 12:00 PM
Permalink | Post RSSRSS comment feed

Using Url rewriting and caching together

The url rewriting...

"Any problem in computer science can be solved with another layer of indirection."
David Wheeler (chief programmer for the EDSAC project in the early 1950s)

URL rewriting is a handy technique to produce much nicer URLs. Instead of http://www.infinitec.de/default.aspx?site=1&subpage=3 a user could use an address like http://www.infinitec.de/exchange/howtos/webdavevents.aspx. When the webserver processes the request, it will rewrite the URL to the webpage that processes the requests and displays the correct content.

In .NET 2.0, this is accomplished by implementing a IHttpModule and registering it in the web.config file.

Here is an example in C#:

    1 using System.Web;

    2 

    3 public class UrlRewriter : IHttpModule

    4 {

    5     #region IHttpModule Members

    6 

    7     public void Dispose() {}

    8 

    9     public void Init(HttpApplication context)

   10     {

   11         context.BeginRequest += context_BeginRequest;

   12     }

   13 

   14     void context_BeginRequest(object sender, EventArgs e)

   15     {

   16         HttpApplication app;

   17 

   18         app = (HttpApplication)sender;

   19 

   20         app.Context.RewritePath("test.aspx");

   21     }

   22 

   23     #endregion

   24 }

The Init method attaches the context_BeginRequest method with the BeginRequest event of the HttpApplication. This implementation redirects each request to the test.aspx in the same virtual directory of the server. In a real world application, this method must extract the necessary information from the original Url and redirect the execution to the correct page for further processing.

To get the sample working, the new module must be registered in the web.config file:

    1 <configuration>

    2   <system.web>

    3     <httpModules>

    4       <add name="UrlRewriter" type="UrlRewriter" />

    5     </httpModules>

    6   </system.web>

    7 </configuration>

You can now open a webbrowser and open any page on the website, regardless if it exists or not. The only restriction is that the extension of the requested page must be registered for the ASP.NET ISAPI filter. Regardless, which page you open, the request is now always processed by the test.aspx file.

When you take a look at the source code of a webpage from your browser, you will notice that the action attribute of the form tag now points back to the test.aspx file, instead of the original URL. A postback would thus reveal the true structure of your website and it might even break the functionality, because the test.aspx file might not know which content to display when called directly.

To solve this problem, the original request path must be restored before the test.aspx file is rendered:

    1 using System.Web.UI;

    2 

    3 public partial class test : Page

    4 {

    5     protected void Page_Load(object sender, EventArgs e)

    6     {

    7         Context.RewritePath("default.aspx");

    8     }

    9 }

For the sake of simplicity, the url is always rewritten to the default.aspx file.

...the caching...

Cashing is a great way to scale your application. Especially when your pages require intensive calculations. Caching is activated on a per-page base by using a page-directive at the top of each page:

    1 <%@ OutputCache Duration="600" VaryByCustom="sitemap" VaryByParam="none" %>

The duration attribute specifies that this page should be cached for 10 minutes (600 seconds). The VaryByParam parameter is set to "none", so any parameters (either POST or GET parameters) are ignored by the caching framework. Finally, the VaryByCustom parameter specifies, that a special method should be called by the the caching framework: The GetVaryByCustomString method, which must be defined in the global.asax file:

    1 <%@ Application Language="C#" %>

    2 

    3 <script runat="server">

    4 

    5     public override string GetVaryByCustomString(HttpContext context, string custom)

    6     {

    7 

    8     }

    9 </script>

...and the problems

Unfortunately, when the caching is used together with URL rewriting, the caching will be unreliable at best...

This is caused by the fact that the caching framework will now cache the output for the wrong url, since it has been rewritten to the test.aspx file. To correct this, the GetVaryByCustomString can be used:

    1 <%@ Application Language="C#" %>

    2 

    3 <script runat="server"> 

    4     public override string GetVaryByCustomString(HttpContext context, string custom)

    5     {

    6         System.Globalization.CultureInfo ci;

    7         string lang;

    8 

    9         if (!custom.Equals("sitemap", StringComparison.CurrentCultureIgnoreCase))

   10             return base.GetVaryByCustomString(context, custom);

   11 

   12         ci = context.Items["CurrentUICulture"] as System.Globalization.CultureInfo;

   13 

   14         lang = ci.DisplayName;

   15 

   16         if (context.Session != null && context.Session["ChosenLanguage"] != null) lang = ((System.Globalization.CultureInfo)context.Session["ChosenLanguage"]).DisplayName;

   17         return (string)HttpContext.Current.Items["OriginalPath"] + ci.DisplayName;

   18     }

   19 </script>

The above implementation returns the original request and the name of the selected language. Thus, a request is served from the ASP.NET cache if the requested path AND the language matches.

This implementation solves the problem that the wrong content ist displayed.


Posted by Henning Krause on Tuesday, December 27, 2005 12:00 AM, last modified on Tuesday, July 26, 2011 9:57 PM
Permalink | Post RSSRSS comment feed

Permission Denied Error with XMLHTTP object

Affected products

  • Microsoft XML Parser 3.0
  • Microsoft XML Parser 3.0 Service Pack 1
  • Microsoft XML Parser 3.0 Service Pack 3

Summary

This article discusses some errors that are received when using the XmlHttp Object to access a secured url from an unsecured page.

Symptoms

When you attempt to access a secure URL by using the XMLHTTP request object from a script on a non-secure Web page, you may receive one of the following error messages:
Access is Denied
This problem only occurs if a non-secure page attempts to access a secure page. Accessing a secure page from another secure page does not generate an error.

Solution

Upgrade the MSXML 3 Parser to Service Pack 5.

References


Posted by Henning Krause on Thursday, January 6, 2005 5:59 PM, last modified on Thursday, January 6, 2005 6:16 PM
Permalink | Post RSSRSS comment feed

Wise for Visual Studio.NET Installer Wizard funktioniert nicht

Betroffene Produkte

  • Wise for Visual Studio.NET 5.0
  • Wise for Visual Studio.NET 5.0

Zusammenfassung

Wenn der Benutzer ein neues Setup Projekt mit Hilfe des Assistenten "Setup Project" erstellen möchte, erscheint folgende Fehlermeldung:
Objekt erwartet
Dieser Fehler tritt auf, wenn die Software auf einem Computer mit nicht-englischem Betriebssystem und Visual Studio.NET installiert wird.

sache

Der Assistent besteht aus einigen HTML-Dateien, die in der Visual Studio Umgebung laufen. Diese prüfen die installierte Sprachversion und versuchen dann externe Skripte einzubinden, die für die jeweilige Sprache entwickelt wurden.
Der Fehler tritt nun auf, da es nur ein Verzeichnis für die englische Version der Software gibt. Wenn nun eine andere Sprache als English installiert ist, sucht die Seite die Skripte in einem nicht vorhandenen Verzeichnis.

Lösung

Der Assistent besteht aus vier HTML Dateien, die in dem Verzeichnis WiseWizards\SetupWiz\Html\1033 unterhalb des Installationsverzeichnis der Software liegen. Jede dieser vier Dateien mus folgenderweise modifiziert werden:
  1. Die Datei mit einem Text-Editor öffnen
  2. Die Zeile
    strURL += window.external.GetHostLocale();
    auskommentieren, und darunter die Zeile
    strURL += "1033";
  3. einfügen. Das Ergebnis sollte so aussehen:
    // strURL += window.external.GetHostLocale();
    strURL += "1033";
  4. Am Ende der Datei ist noch ein Skript-Block mit dem folgenden Inhalt:
    strPath += window.external.GetHostLocale();
  5. Auch diese Zeile muss wieder auskommentiert werden, und darunter die Zeile
    strPath += "1033";
  6. eingefügt werden. Das Ergebnis sollte dann so aussehen:
    // strPath += window.external.GetHostLocale();
    strPath += "1033";
  7. Die Änderungen speichern.

Posted by Henning Krause on Friday, December 31, 2004 1:56 PM, last modified on Tuesday, July 26, 2011 9:56 PM
Permalink | Post RSSRSS comment feed

Implement an UDP multicast client/server communication

Affected products

  • .NET Framework 1.0
  • .NET Framework 1.1

Summary

This article explains, how to implement a multicast client/server communication using the UDP protocol.

Description

One feature of the UDP Protocoll is the support for multicast messages. This are messages, that are sent from one host to multiple clients. Additionally, the sending host does not need to know the destination of the packets. Instead, it sends the packet to a special IP address (in the range from 224.0.0.0 to 239.255.255.255). This address is called a multicast group.
The client, on the other side, registers itself to this address on the next hop on the route to the source host. This process is called "joining a multicast group". This next hop is either a router or the destination host. If it is a router, it will propagate this registration forward to the next router, until the destination host is reached.
The MSDN documentation contains an article that covers this topic, but it has two drawbacks:
The client component described in that article does only allow one client on one machine, and
the code doesn't work.

Solution

For the client component, use the following code:
multicastListener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,ProtocolType.Udp);
multicastListener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
multicastListener.Bind(new IPEndPoint(IPAddress.Any, 65000));
multicastListener.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(new IPAddress("224.0.0.42"), IPAddress.Any));
This will create a socket that is bound to port 65000. The second line sets the socket in a non-exclusive state, thus allowing other process to bind to the same port. Finally, the fourth line will cause the socket to join the specified multicast group on all network interfaces.
The following code makes up the server part. It will create a socket, that will open the multicast group on the address 224.0.0.42, port 65000.
multicastSender = new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp );
multicastSender.Bind(new IPEndPoint(IPAddress.Any, 0));
multicastSender.Connect(new IPEndPoint(new IPAddress("224.0.0.42", 65000)));
To send messages to the multicast group, the following code is used:
buffer = Encoding.UTF8.GetBytes("Hello world!");
multicastSender.Send(buffer);

More informations

The UDP protocoll is a connectionless, non-reliable protocol. This means, that no connection has to be established before one can send data. Further, it is neither guaranteed that the packets are received by the remote host in the order they were sent, nor that they are received at all.
The addresses 224.0.0.1 and 224.0.0.2 are reserved adresses. The first one is a global group, similar to the broadcast addresses of the IP protocol. The second one is a global adress for routers only.
UDP multicast is described in RFC 1112.
Not all router support the IGMP protocol, which is used for multicast group subscription. Especially over the internet, UDP multicast will most likely fail. It is therefore best suited for intranet applications.

Posted by Henning Krause on Friday, December 31, 2004 1:54 PM, last modified on Friday, December 31, 2004 2:26 PM
Permalink | Post RSSRSS comment feed

Programmatically set the value of META-Tags with ASP.NET and C#

Affected products

  • .NET Framework 1.0
  • .NET Framework 1.1

Summary

This article explains, how to set the attributes of a META-Tag in an ASP.NET website.

Description

Since there is no META-Tag server control within the .NET framework, and the META tags are in the <head> section, thus outside of the <form> section, it is a little bit tricky to access these tags.

Solution

  1. First, create the desired Tag. In this article, a METAREFESH tag will be created. So open the ASP.NET page and insert the following line into the <head> section:
    <meta id="metaRefresh" runat="Server"/>
  2. Now, open the codebehind file, and add the following variable declaration on the class level:
    protected System.Web.UI.HtmlControls.HtmlControl metaRefresh
  3. Note, that the id in the ASP.NET file and the name of the variable must be identically.
  4. In The Page_Load event, add the following code:
    metaRefresh.Attributes["HTTP-EQUIV"] = "refresh";
    metaRefresh.Attributes["content"] = "3;URL=" + myUrl
  5. This code will cause the browser to do a METAREFRESH after 3 seconds. The user will then be redirected to the url specified in the myUrl variable.

Other informations

If you are using WebUserControls and want to access the META tags from within these controls, you should store the desired values in the session object and put the above code into a PreRender event handler. This handler is called after all controls have been loaded. You can then take the values from the Session object and put tehm into the meta tag.

Posted by Henning Krause on Friday, December 31, 2004 1:50 PM, last modified on Tuesday, July 26, 2011 9:57 PM
Permalink | Post RSSRSS comment feed

HttpWebRequest fails when several connections are made concurrently

Affected products

  • .NET Framework 1.0
  • .NET Framework 1.1

Summary

When making several connections concurrently with the HttpWebRequest class, the request objects fail with an exception.

Symptoms

When making several connections concurrently (more than 12 on a single processor machine) with the HttpWebRequest class, the request objects fail with an exception.
If these calls are made from methods running on ThreadPool thhreads, the maximum number of connections is further reduced.

Cause

The HttpWebRequest uses two threads for each connection from the ThreadPool. This pool has a maximal capacity of 25 on one processor machines. Regularly, if the pool is full, it would queue further requests. But the HttpWebRequest class checks whether two threads are available before putting its requests into the queue. It fails with an exception, when there are less than two threads available.

Status

This behaviour is by design.

Solution

Keep concurrent connections as low as possible, and don't initiate requests from methods running on ThreadPool threads.

Other information

To keep the concurrent connections low, you can use the Advanced Threadpool from the Toolbox area of this page. This class implements a thread pool, which is independent of the ThreadPool class. With this class, you can set the maximium number of concurrent threads, so that the limit of the ThreadPool is never reached.

Posted by Henning Krause on Friday, December 31, 2004 1:09 PM, last modified on Friday, December 31, 2004 1:10 PM
Permalink | Post RSSRSS comment feed

HttpWebRequest Class has poor performance

Affected Products

  • .NET Framework 1.0
  • .NET Framework 1.1

Summary

The HttpWebRequest class performs poorly when sending requests to a server which contain a body.

Symptoms

The HttpWebRequest class performs poorly when sending requests which contain body data to a server. When monitoring the network traffic the following behaviour is seen:
  • The client sends the header of the request to the server.
  • After 350ms the rest of the request is send to the server.

Cause

The HttpWebRequest class waits for a HTTP1.1/100-Continue message before sending the body of the request. Additionally, the class supports the Nagle algorithm, which prevents the sending of many small packets to the same target. Instead, the server waits approximately 200 milliseconds, if there are other packets to be send to the same target. It then combines these requests in one packet.

Status

Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.
A hotfix exists (QFE810814) for version 1.0 of the Framework in the languages english and german. The patch is localized for other languages on request. Since it is a quick fix engineering (QFE), it can only be obtained directly from Microsft Support (PSS).
For the .NET Framework 1.1, no patch is necessary, since the behaviour can be controlled programmatically:
HttpWebrequest webRequest = (HttpWebRequest) Webrequest.Create("http://myserver/myfile");
webRequest.ServicePoint.Expect100Continue = false;
webRequest.ServicePoint.UseNagleAlgorithm = false;

Other Information

Note that you must have installed service pack 2 for the .NET Framework 1.0 before applying the patch.
Additionally, some configuration entries must be made in the machine.config file:
  1. Create a new <settings> section within the <system.net> section with the following content:
    <settings>
    <servicePointManager useNagleAlgorithm="false" />
    <servicePointManager expect100Continue="false" />
    </settings>
  2. In order for the .NET Framework to recognize this new section a settings sectionGroup handler needs to be added to the <configSections> portion of machine.config file:
    <sectionGroup name="system.net" >
    <section name="settings" type="System.Net.Configuration.NetConfigurationHandler, System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
    </sectionGroup>

Posted by Henning Krause on Thursday, December 30, 2004 6:36 PM, last modified on Thursday, July 14, 2011 10:32 PM
Permalink | Post RSSRSS comment feed