Intro
Sooner or later every developer after development stage faces deployment stage. This stage turns out in developing another application, namely installer.
There are a lot of installers out there. Here I will enumerate some NSIS - Nullsoft scriptable install system, InstallShield, WISE, WiX and a lot of others. The latter use Microsoft Installer technology. All of them, except Nullsoft installer, produce .msi and other MS Installer files.
Properties in MSI
Since MSI file is a collection of tables, properties are placed in special table called, I think you will guess - "Property" :8-).So, what’s so special about these properties?
Custom Actions and Properties
Every installer developer should be aware that there are 2 types of properties in MSI. Values from Properties table are used by an installer as global variable during install process.
Information about types of properties is of special value for "custom actions" (CA) developers. CAs are special programs (.exe) or modules (.dll) that are called during installation process to perform special actions.
Now, let’s get back to properties...
Docs say:
- Private properties: The installer uses private properties internally and
their values must be authored into the installation database or set to values determined by the operating environment.
- Public properties: Public properties can be authored into the database and changed by a user or system administrator on the command line, by applying a transform, or by interacting with an authored user interface.
You will ask, how Installer determines which are private and which are public?
It is very simple public properties must be uppercase, and that’s it.
So, if your custom action stopped working and the problem is that it cannot read property from msi, then the first thing you should check is if this property is public.
Friday, May 05, 2006
public vs private properties in MSI
Опубліковано V о 5/05/2006 07:00:00 PM 0 коментарі
Мітки: Installers
Sunday, March 19, 2006
Issues when using MarshalByRefObject instances from several application domains
At first let’s consider why we need to inherit our classes from MarshalByRefObject.
The reason is very simple - we want use them in separate application domains.
Let’s suppose we have to appdomains: appdomain1 and appdomain2.
(In this post I will not cover the details of application domain creation)
public class MainAppD : MarshalByRefObject
{
public SlaveAppD slaveAppDomain;
public void DoInPrimaryAppDomain()
{
}
}
//this class will be executing on second app domain
public class SlaveAppD : MarshalByRefObject
{
public MainAppD mainAppDomain;
public void DoInSlaveAppDomain()
{
}
}
What's wrong with these classes?
Recently I had similar scenario, and wondered why did my objects get disconnected from other appdomain.
When object is disconnected and you try to call its methods you get RemotingException...
Let’s consider lifetime of the above mentioned
class members that are references, namely SlaveAppD.slaveAppDomain and MainAppD.mainAppDomain
will become __TransparentProxy references. All calls will go through these transparent proxies.
Notions of proxies and application domains are directly connected with notion lifetime.
If we will consider classes above neither of them cares about its lifetime.
MarshalByRefObject has InitializeLifetimeService() method that returns time lease. The lease specifies
how long this object can be "alive" (Basically this means that proxy connection is alive).
The default lease value is 5 minutes. To increase lifetime
one has to override InitializeLifetimeService. Lets set lease time to 15.
public override Object InitializeLifetimeService()
{
ILease lease = (ILease)base.InitializeLifetimeService();
if (lease.CurrentState == LeaseState.Initial)
{
lease.InitialLeaseTime = TimeSpan.FromMinutes(15);
lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
}
return lease;
}
If you want infinite proxy connection lifetime the you simply return null.
//Infinite lifetime lease
public override Object InitializeLifetimeService()
{
return null;
}
Опубліковано V о 3/19/2006 12:15:00 AM 0 коментарі
Мітки: .NET
Saturday, March 18, 2006
Blog connectivity
In order to stay always connected to this blog ( if I will change hosting ), please use this link for syndication link
Опубліковано V о 3/18/2006 02:06:00 PM 0 коментарі
Thursday, March 02, 2006
Beware of asynchronous methods calls that can complete synchronously. Part 1
In .NET every method can be executed asynchronously, it means that it will be executed in the separate thread, typically ThreadPool thread. Here is sample code…
class Program
{
public delegate void LongMethodDelegate();
static void Main(string[] args)
{
Console.WriteLine("Main thread: {0}",
Thread.CurrentThread.ManagedThreadId);
LongMethodDelegate @delegate =
new LongMethodDelegate(LongRunningMethod);
IAsyncResult ar = @delegate.BeginInvoke(
new AsyncCallback(OnComplete), null);
ar = @delegate.BeginInvoke(new AsyncCallback(OnComplete), null);
//@delegate.EndInvoke(ar);
Console.ReadLine();
}
static void LongRunningMethod()
{
Thread.Sleep(10000); //long running task
Console.WriteLine("--------- LongRunningMethod");
Console.WriteLine("Executing on thread: {0}",
Thread.CurrentThread.ManagedThreadId);
}
static public void OnComplete(IAsyncResult ar)
{
Thread thread = Thread.CurrentThread;
Console.WriteLine("--------- OnComplete");
Console.WriteLine("Completed on thread: {0}\n" +
"Synchronously: {1}\n" +
"ThreadPool thread: {2}\n" +
"IsBackground thread: {3}",
thread.ManagedThreadId,
ar.CompletedSynchronously.ToString(),
thread.IsThreadPoolThread.ToString(),
thread.IsBackground.ToString());
}
}
Everything is pretty simple here, LongRunningMethod() is executed on the separate thread, OnComplete is called when LongRunningMethod()is completed. The thread that completes the work is called WorkerThread.
While using this approach – method that is being called asynchornously will be executed on the separate thread… However, if you noticed IAsyncResult has CompletedSynchronously property. What for? It is a good question, and I hope soon it will be answered :8-)
Опубліковано V о 3/02/2006 01:00:00 AM 0 коментарі
Мітки: .NET, tips'n'tricks
Monday, February 27, 2006
Ukrainian version of blog started
Since I live in Ukraine ( not so small republic in the central-east Europe ) I decided to start a mirror blog in Ukrainian.
You can find it here
Опубліковано V о 2/27/2006 08:24:00 PM 0 коментарі
Sunday, January 22, 2006
Proxy Server behavior with different HTTP protocol versions
In one of my previous posts I mention HTTP tunnel application that I’m working on. Basically it can be considered http proxy. Lets see now what difficulties can be encountered when implementing proxy server
At present there are 2 official versions of HTTP protocol – 1.0 and 1.1 From proxy point of view most significant difference between them is that be default 1.0 doesn’t support persistent connections with web server, while the other ( 1.1 ) by default supports them. Also to control web server behavior Connection header can be specified. That is Connection: close will signal web server to close connection when response was sent.
In this situation proxy server can have several option modes:
- operate as if there is no proxy server at all – that is if client uses HTTP 1.0 then proxy also uses HTTP 1.0 and the same for HTTP 1.1
- for the client side (local) use client specified protocol, for web server connection (remote) maintain other protocol. As an example proxy server with client works under HTTP 1.0 and with server under HTTP 1.1. Proxy server doesn’t ignore Connection header
- the same as the above except proxy server ignores Connection header that is proxy server by all means tries to maintain persistent connection.
Last scenario can be used when the remote endpoint isn’t web server but another proxy.
In RFC 2616 [HTTP/1.1] proxy behavior is described like this:
“It is especially important that proxies correctly implement the
properties of the Connection header field as specified in section
14.10.
The proxy server MUST signal persistent connections separately with
its clients and the origin servers (or other proxy servers) that it
connects to. Each persistent connection applies to only one transport
link.
A proxy server MUST NOT establish a HTTP/1.1 persistent connection
with an HTTP/1.0 client (but see RFC 2068 for information and
discussion of the problems with the Keep-Alive header implemented by
many HTTP/1.0 clients).”
From this part of the RFC we can see that the last operation mode can be considered as “hard optimization”.
Another tricky moment while implementing proxy server for HTTP 1.1 is Content-Length header. Generally setting this header simplifies content retrieval from the server. However, when content size is big - modern web servers can omit Content-Length header in order to boost performance and reduce the amount of resources allocated on the server. In practice we have the situation, when client is receiving data without any clue how much data is still not received or where will be the end of the data stream.
Proxy server has to know about this issue and handle it correctly. Here we also have 2 options: proxy server can receive whole data from the server, set Content-Length header and transmit whole data to the server, and the second option will be redirecting data stream to the client as if there is no proxy at all. One of the pitfalls here is that if content is too large proxy server can consume great amount of system resources ( 1 option ). While in the 2-nd mode proxy doesn’t know when data stream will finish.
At first I’ll implement 1 mode ( that is caching content on the proxy and then sending it to client ), then probably I’ll experiment with the second option.
Опубліковано V о 1/22/2006 04:18:00 AM 3 коментарі
Wednesday, November 09, 2005
Full and Partial Assembly Names
Preface
Recently my wife encountered weird problem with PropertyGrid control. As you know this control displays object properties and gives the posibility to edit them. If object has properties that return CollectionBase types, property grid displays nice dialog that allows editing collection items.
Type of the edit dialog is specified by the Editor attribute. ( see MSDN for details ).
The Problem
Property called Items returns CollectionBase type. Namely StringCollection.
The snippet below illustrates the situation:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor("System.Windows.Forms.Design.StringCollectionEditor, System.Design",
"System.Drawing.Design.UITypeEditor, System.Drawing")]
public StringCollection Items
{
//common stuff goes here
}
Everything looks fine, however when the object with this property is given to PropertyGrid, collection edit
dialog doesn't recognize its true string nature. Instead of StringCollectionEditor we observer common editor dialog,
where collection items have type System.Object. Somehow PropertyGrid didn't recognized the attribute, or attribute
contents...
Stephen Toub in his blog directly addresses
this problem. Yes the problem was with partial names. So the solution is very simple if you're the owner of the
code, where that attribute is specified, and you can easily chage it.
So, the working version will look like:
[Editor(
"System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
"System.Drawing.Design.UITypeEditor, System.Drawing, Version=1.0.5000.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public StringCollection Items
{
//common stuff goes here
}
For those who use 3-d party classes and have no access to source code, there are 2 solutions:
1) modify the DEVENV environment variable
2) put System.Design.dll assembly to the folder, where your app resides
First way isn't good as it may affect other applications that rely on that variable and it is not safe.
My wife chose second way, she just added System.Design.dll to the references list and set "Copy local" property to true.
Опубліковано V о 11/09/2005 03:20:00 PM 0 коментарі
Мітки: .NET
Monday, September 26, 2005
Server side: ETag VS Cache-Control max-age=xxxx or Expiration VS Validation
I will not cover here the whole topic of the web caching, but there things, which I'd
like to mention. They are the two caching mechanism:
1) is configured in the server ( in IIS we can set expiration date or expiration timeout ( e.g. max-age ) and on Apache we even can set cache policy for different content types )
2) no configuration in the server ( client uses "ETags" for cache validation ) - the default one.
Now lets consider 1st way, we configure web-server and set expire time as 1 hour ( max-age = 3600 ). What will now happen? Client will download the resource with the header - Cache-Control: max-age = 3600, store this value and will also store the date, when that resource was downloaded. Then every time during 1 hour when client browser
receives reference to the resource he will check download date & max-age value of it, and if the content is up-to-date, browser will not send request to the server, and it will use cached resource.
On the other hand ( 2nd way ) server has no configuration settings. Every resource downloaded from the server has it own "ETag". Next time, when browser accesses the resource it sends request to the server, and server sends response, containing error - 304 ( not modified ). This code signals client to use cached version of the resource.
While analyzing these two techniques we can come to the conclusion:
1) when using 1st way - we reduce the number of server roundtrips, thus have better network performance.
2) when using 2nd way - we have greater number of roundtrips to check the resource ETag.
The pros and cons are the following here:
1st way, greater network performance but cache will be invalidated only after period of time 2nd way, lower network performance but cache will be invalidated correctly, when resource will be changed.
The above said in the HTTP spec it is stated as
"The former reduces the number of network round-trips required for many operations; we use an “expiration” mechanism for this purpose (see section 13.2). The latter reduces network bandwidth requirements; we use a “validation” mechanism for this purpose (see section 13.3)."
From the HTTP spec:
"Caching would be useless if it did not significantly improve performance. The goal of caching in HTTP/1.1 is to eliminate the need to send requests in many cases, and to eliminate the need to send full responses in many other cases."
Update: actually 1-st and 2-nd methods can also be used togther. Using them combined can reduce not only the number of requests but also response size.
For instance if two methods are used together: the resource will at first expire and after that it will be checked (validated) for change.
Опубліковано V о 9/26/2005 07:56:00 PM 11 коментарі
Мітки: Networking, tips'n'tricks
Wednesday, September 21, 2005
neural networks
In the place where I study, we started new course - Neural Networks. The teacher gives us only mathematical basis, however, there is huge load of materials on the Net, with the applicable samples and source code...
http://www.csharphelp.com/archives2/archive407.html
http://www.kdkeys.net/forums/ShowPost.aspx?PostID=3069
http://franck.fleurey.free.fr/NeuralNetwork/
Опубліковано V о 9/21/2005 10:41:00 AM 1 коментарі
Monday, July 25, 2005
Writing .NET proxy/tunnel engine for the HTTP
In my home network I have 2 computers: one of them is connected to the internet via dial-up connection. My pc has no modem, that is why to access the Internet I have to work on the other PC. I know that there is a bunch of gateway/proxy software that has the required functionality for tunneling http requests, but they aren’t open source and cannot be extended.
My goal is write extensible proxy engine, with default http tunneling implementation. And in the future other protocols may be added to it.
So, for now I’m studying RFC 2617 (Hypertext Transfer Protocol)…
Опубліковано V о 7/25/2005 03:51:00 PM 1 коментарі