Wednesday, June 30, 2010

Business Logic Toolkit for .NET

NServiceBus

http://www.techdays.ru/videos/2295.html
http://www.nservicebus.com/Documentation.aspx

Tuesday, June 29, 2010

Анонимная рекурсия на C# и лямбды

Лямбды есть анонимные функции, а рекурсия требует определения имен.
Определение функции, которая вычисляет число Фибоначчи:

Func fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;

Но работать это не будет, т.к. компилятор выдаст ошибку:
Use of unassigned local variable 'fib'

Проблема в том, что правая сторона выражения оценивается до того, как fib будет определена.

Быстрый обход этой проблемы - присвоить fib null, то есть явно определить fib перед тем, как она будет использована.

Func fib = null;
fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
Console.WriteLine(fib(6));                        // displays 8

Но это решение не является настоящей рекурсией. Рекурсия требует, чтобы функция вызывала саму себя. В данном случае функция fib просто вызывает делегат, на который ссылается локальная переменная fib. На первый вгзгляд, это игра слов, но рассмотрим следующий пример:

Func fib = null;
fib = n => n > 1 ? fib(n - 1) + fib(n - 2) : n;
Func fibCopy = fib;
Console.WriteLine(fib(6));                        // displays 8
Console.WriteLine(fibCopy(6));                    // displays 8
fib = n => n * 2;
Console.WriteLine(fib(6));                        // displays 12
Console.WriteLine(fibCopy(6));                    // displays 18

Можно заметить, как меняется результат вызова fib и даже вызов fibCopy отличается от вызова fib. Этот беспредел можно остановить, передавая функцию, которая будет использоваться для рекурсивного вызова:

(f, n) => n > 1 ? f(f,n - 1) + f(f,n - 2) : n

Таким образом, лямбда выглядит почти так же за тем исключением, что она первым параметром принимает функцию f. Когда вызывается фунцкия f, нужно передать ее в себя первым аргументом.

Чтобы это реализовать и преобразовать лямбду к делегату, необходимо определить тип делегата. Начнем с типа fib, Func. Возвращаемый тип - int, принимаемым вторым аргументов типом также должен быть int. Что касается первого аргумента, им должен быть делегат, который должен вызываться с теми же аргументами, которые мы определяем в данном случае, что и есть рекурсия:

delegate int Recursive(Recursive r, int n);

Этот делегат можно обобщить через параметризацию аргумента и возвращаемого типа:

delegate R Recursive(Recursive r, A a);

Теперь можно использовать лямбду, определенную выше:

Recursive fib = (f, n) => n > 1 ? f(f,n - 1) + f(f,n - 2) : n;
Console.WriteLine(fib(fib,6));                      // displays 8
Хотя это является решением, выглядит оно не так красиво, как первоначальный код...

(продолжение следует)

Friday, June 11, 2010

Ошибки файловых операций - I/O Error

Исходный список можно посмотреть здесь: http://support.microsoft.com/kb/320081

Интерес представляют 4 и 6, поскольку в последнее время часто приходилось сталкиваться с этим.
Такой файл средствами .NET невозможно ни удалить, ни переименовать.
Вкратце одно из возможных решений:
1. Преобразовать файл к короткому имени.
2. Выполнить копирование файла в новое имя при помощи CopyFileEx


  1.     [Flags]
  2.     public enum CopyFileFlags : uint
  3.     {
  4.       COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
  5.       COPY_FILE_RESTARTABLE = 0x00000002,
  6.       COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004,
  7.       COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008
  8.     }
  9.  
  10.     public enum CopyProgressCallbackReason : uint
  11.     {
  12.       CALLBACK_CHUNK_FINISHED = 0x00000000,
  13.       CALLBACK_STREAM_SWITCH = 0x00000001
  14.     }
  15.  
  16.     public enum CopyProgressResult : uint
  17.     {
  18.  
  19.       PROGRESS_CONTINUE = 0,
  20.       PROGRESS_CANCEL = 1,
  21.       PROGRESS_STOP = 2,
  22.       PROGRESS_QUIET = 3
  23.     }
  24.  
  25.     public delegate CopyProgressResult CopyProgressRoutine(
  26.       long totalFileSize,
  27.       long totalBytesTransferred,
  28.       long streamSize,
  29.       long streamBytesTransferred,
  30.       uint dwStreamNumber,
  31.       CopyProgressCallbackReason dwCallbackReason,
  32.       IntPtr hSourceFile,
  33.       IntPtr hDestinationFile,
  34.       IntPtr lpData);
  35.  
  36.     public static bool XCopy(string oldFile, string newFile)
  37.     {
  38.       var pbCancel = 0;
  39.       return CopyFileEx(oldFile, newFile, CopyProgressHandler, IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE);
  40.     }
  41.  
  42.     public static CopyProgressResult CopyProgressHandler(long total, long transferred, long streamSize,
  43.                                long streamByteTrans, uint dwStreamNumber,
  44.                                CopyProgressCallbackReason reason, IntPtr hSourceFile,
  45.                                IntPtr hDestinationFile, IntPtr lpData)
  46.     {
  47.       return CopyProgressResult.PROGRESS_CONTINUE;
  48.     }
  49.  
  50.     [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
  51.     [return: MarshalAs(UnmanagedType.Bool)]
  52.     public static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName,
  53.                        CopyProgressRoutine lpProgressRoutine, IntPtr lpData, ref Int32 pbCancel,
  54.                        CopyFileFlags dwCopyFlags);
  55.  
  56.     [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
  57.     public static extern int GetShortPathName([MarshalAs(UnmanagedType.LPTStr)] string path,
  58.                          [MarshalAs(UnmanagedType.LPTStr)] StringBuilder shortPath,
  59.                          int shortPathLength);
  60.  
  61.  
  62.     public static string UPath(string path)
  63.     {
  64.       const string PreNet = @"\\?\UNC\";
  65.       const string PreLoc = @"\\?\";
  66.  
  67.       var isNetworkPath = path.StartsWith(@"\\");
  68.       var pre = isNetworkPath ? PreNet : PreLoc;
  69.       var res = path.StartsWith(pre) ? path : pre + path;
  70.  
  71.       return res.EndsWith(@"\") ? res.Substring(0, res.Length - 1) : res;
  72.     }
  73.  
  74.     public static FileInfo XCopy(FileInfo fileInfo, string target)
  75.     {
  76.       var filename = Win32IOManaged.UPath(Path.GetDirectoryName(fileInfo.FullName)) + @"
  77. \" + fileInfo.Name;
  78.       var buffer = new StringBuilder(255);
  79.       var length = Win32IOManaged.GetShortPathName(filename, buffer, buffer.Capacity);
  80.  
  81.       if (length <= 0)
  82.       {
  83.         return null;
  84.       }
  85.  
  86.       var result = Win32IOManaged.XCopy(buffer.ToString(), target);
  87.       var lasterror = Marshal.GetLastWin32Error();
  88.  
  89.       if (!result || lasterror != 0)
  90.       {
  91.         return null;
  92.       }
  93.  
  94.       return new FileInfo(target);
  95.     }
* This source code was highlighted with Source Code Highlighter.

Monday, June 7, 2010

CallContext Data Slots, CallContext


CallContext - удобный способ обмена информации между клиентом и сервером.
CallContext записывает данные в Thread Local Storage.


Чтобы для каждого потока информация была уникальной, необходимо использовать методы
SetData и GetData, но передаваться через границы AppDomain они будут только в том случае, если унаследованы от интерфейса ILogicalThreadAffinative.
Объекты, сохраненные через метод LogicalSetData, будут передаваться через границы домена даже в том случае, если они не унаследованы от ILogicalThreadAffinative.

Logical[Get/Set]Data добавляет/удаляет значения из Hashtable. 
Hashtable живёт в инстансе класса LogicalCallContext, который, в свою очередь, живёт внутри ExecutionContext, а тот — внутри Thread. Чтобы не разматывать весь стек: при переходе в новый контекст вызывается метод LogicalCallContext.Clone, а при возврате — LogicalCallContext.Merge.
Merge заменяет значения в Hashtable теми, что были установлены в новом контексте. 

И может выполниться в другом потоке, если EndInvoke был вызван асинхронно В результате значение вот этого абсолютно непредсказуемо:
 
Stack<int> stack = (Stack<int>)(CallContext.LogicalGetData("MyContext"));
 
Вот дополнительная информация:

The LogicalCallContext is able to flow bi-directionally through an async invocation or a .net remoting call. When you call EndInvoke, the child context's LogicalCallContext is merged back into the parent's, as you have observed. This is intentional, so that callers of remote methods can get access to any values set by the remote method. You can use this feature to flow data back from the child, if you'd like.
Debugging this with the help of the .NET Framework source stepping, there are explicit comments to this effect:

in System.Runtime.Remoting.Proxies.RemotingProxy.Invoke:
    case Message.EndAsync: 
         // This will also merge back the call context
         // onto the thread that called EndAsync
         RealProxy.EndInvokeHelper(m, false);
in System.Runtime.Remoting.Proxies.RealProxy.EndInvokeHelper:
    // Merge the call context back into the thread that
    // called EndInvoke 
    CallContext.GetLogicalCallContext().Merge(
         mrm.LogicalCallContext);
 
If you want to avoid having the data merge, it's pretty easy to skip, just avoid calling EndInvoke from the main thread. You could for example use ThreadPool.QueueUserWorkItem, which will flow the LogicalCallContext in but not out, or call EndInvoke from an AsyncCallback.
Looking at the example on the Microsoft Connect site, the reason that you're not seeing the LogicalSetData value get flowed back from the RunWorkerCompleted call is that BackgroundWorker does not flow the context back. Also, remember that LogicalSetData is not the same as thread-local storage, so it doesn't matter that RunWorkerCompleted happens to be running on the UI thread -- the LogicalCallContext there is still a child context, and unless the parent explicitly flows it back by calling EndInvoke from the spawning thread, it will be abandoned. If you want thread-local storage, you can access that from Thread, like so:

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Thread.SetData(Thread.GetNamedDataSlot("foo"), "blah!!");
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var val = (string)Thread.GetData(Thread.GetNamedDataSlot("foo"));
        MessageBox.Show(val ?? "no value");
    }

(from: http://dotnetmustard.blogspot.com/2008/08/identifying-differences-between.html)

Recently I was working on a server side caching strategy for permissions data. The key to the strategy was to place a user's permissions returned from a database call into the CallContext of WCF service. The code to do this looked something like this...

CallContext.SetData("permissionsKey", myPermissionsData);

All subsequent requests for permissions data would then be returned from the CallContext's cache permissions, thereby saving me from having to make redundant database calls for data that I already have.

myPermissionsData = (PermissionData)CallContext.LogicalGetData("permissionsKey")

Simple caching strategy...

During my testing I found that my cached data was not being returned. After further investigation I realized that I was setting the data using the CallContext's SetData method, but I was getting the data using the CallContext's LogicalGetData method. Come to find out, these are not the same. Seems there is a LogicalGetData method, LogicalSetData method, GetData method and SetData method on the CallContext object. So, it was a simple fix to use the LogicalSetData method in conjunction with the LogicalGetData method when implementing my caching strategy.

But why are there two methods that seemingly do the same thing? The documentation on MSDN doesn't really specify the differnce between the two.

Well... after doing some resarch and finding a post by Lucian Bargaoanu on the subject it seems that the difference has to do with AppDomains. Come to find out there is a LogicalCallContext and an IllogicalCallContext. LogicalCallContext will flow across appdomains. It will do this regardless of what type of object you have placed in context. The object doesn't have to implement ILogicalThreadAffinitive. When you call SetData with an ILogicalThreadAffinitive object, the data is set in the LogicalCallContext. When you call GetData it will first look in the LogicalCallContext and then in the IllogicalCallContext. You cannot have the same key in both CallContext(s).

In summary, objects stored using SetData will only flow across AppDomains if they implement ILogicalThreadAffinitive. Objects stored in LogicalSetData will flow across AppDomains even if they don't implement ILogicalThreadAffinitive. LogicalSetData handles seems to handle the ILogicalThreadAffinitive implementation for you.

Friday, June 4, 2010

Y Combinator

Wednesday, June 2, 2010

Flash Cookies and Supercookies

Дополнительная ссылка:
Сниффинг истории посещений через чтение ‘visited’ стиля ссылок и через Cache timing


Several browsers give you the option to select a privacy option that supposedly lets you surf the Web without leaving fingerprints. Don't believe it.
That option generally stops the browser from storing the URLs of pages you've visited in a pull down under the browser bar or recently visited tab. But it does nothing to conceal the pages and images you've viewed from advertisers who want to serve tailored ads to you, or even worse, from assorted snoops including private detectives and law enforcement agents.
The old solution, simply deleting cookies or clicking a setting that keeps your browser from accepting them, is much less effective than it used to be. That's because many Web sites are now using something called a "Flash cookie," which is maintained by the Adobe Flash plug-in on behalf of Flash applications embedded in Web pages, says Peter Eckersley a researcher with the Electronic Frontier Foundation.
Unlike standard cookies, flash cookies and a variation known as a supercookie are stored outside of the browser's control and users cannot view or directly delete them and they never expire. Flash cookies can track users in all the ways traditionally HTTP cookies do, and can be stored or retrieved whenever a user accesses a page containing a Flash application, says Eckersley. 

Data Structures And Algorithms Alfred V. Aho

Tuesday, June 1, 2010

DryadLINQ

DryadLINQ is a simple, powerful, and elegant programming environment for writing large-scale data parallel applications running on large PC clusters.


Differential Privacy

Powered by Blogger.