суббота, 2 апреля 2011 г.

Способы размещения служб WCF. Часть 3: размещение в среде Windows Process Activations Services


Windows Process Activation Service (WAS)  - это среда, которая управляет активацией и жизненным циклом рабочих процессов, в контексте которых выполняется служба WCF. Модель WAS, в отличии от IIS предоставляет возможность использовать не только протокол HTTP, но и такие протоколы как TCP, Pipes и др. WAS является дополнением к IIS и включена в Windows Server 2008.
WAS имеет следующие преимущества:
  • Автоматический запуск/остановка рабочего процесса службы при обращении клиентов как с использованием протокола HTTP, так и с использованием иных протоколов. Такой способ запуска и остановки приложений обеспечивают более эффективное использование ресурсов сервера. 
  • Централизованное управление службами
  • Использование всех преимуществ IIS

Рассмотрим пример размещения службы WCF в среде WAS, которая должна быть автоматически установлена в Windows Server 2008 и выше. Для того, чтобы убедится, установлена ли WAS на сервере открывает окно ServerManager и проводнике слева выбираем пункт Features. Далее жмем кнопку Add Features и в открывшемся окне в списке дополнений находим WAS:
Так же необходимо убедиться, что в самом .Net Framework включена опция взаимодействия с WCF через протокол, отличный от HTTP: 
На рисунке видно, что включена активация через HTTP (возможность размещения служб WCF в контексте IIS), так и активация через отличный от HTTP протокол (в этом случае, служба может быть размещена в контексте WAS).
Далее создаем виртуальный каталог в IIS, где будет размещаться наша служба. Я добавил виртуальный каталог в сайт Default Web Site. 
Следующим шагом скопируем файлы службы в этот каталог. Обязательно, чтобы служба имела файл *.svc (см. Часть 1: размещение службы в IIS). В файле конфигурации службы определим привязку, отличную от HTTP:


      
        
      
    


Теперь настроим конфигурацию самого WAS. Все настройки конфигурации WAS хранятся в файле ApplicationHost, который находится в файле %windir\System32\inetsrv\config. Изменять данный файл можно как руками так через специальную утилиту appcmd.exe в папке %windir\System32\inetsrv\.
Задача настроек WAS состоит в следующем:
  • Нужно задать конкретный порт, который будет открыт на прослушку
  • Нужно разрешить виртуальному приложению, где размещена служба, использовать нужный протокол
С синтаксисом appcmd.exe можно ознакомиться, набрав в командной строке appcmd.exe /? Либо по этой ссылкеhttp://learn.iis.net/page.aspx/114/getting-started-with-appcmdexe
Выполним следующие команды с правами администратора:
appcmd.exe set site "Default Web Site" –+bindings.[protocol=’net.tcp’,bindingInformation=’808:*’]

Здесь мы выполняем команду set (конфигурация виртуальной директории), для объекта site (у нас указано название сайте Default Web Site в ковычках). Эта команда добавляет привязку узла к протоколу net.tcp в веб-узел по умолчанию, ожидающему передачи данных по протоколу TCP на порту 808 с любым именем узла.

appcmd.exe set app "Default Web Site/WcfWAS"/enabledProtocols:http,net.tcp

Этой командой сообщаем, что наша служба (обратите внимание, что используется объект app, вместо site) будет работать через протоколы HTTP и TCP. Таким образом, после выполнения этой команды к службе можно будет обратиться по адресу net.tcp://server/WcfWAS
Все, служба WCF размещена. Теперь к ней можно обращаться по адресуnet.tcp://server/WcfWAS.
Можно выполнить и обратные команды: запретить службе работать через TCP иудалить привязку протокола TCP.
appcmd.exe set app "Default Web Site/WcfWAS"/enabledProtocols:http

appcmd.exe set site "Default Web Site" --bindings.[protocol=’net.tcp’,bindingInformation=’808:*’]


четверг, 31 марта 2011 г.

Способы размещения служб WCF. Часть 2: размещение службы в контексте любого Windows-приложения


Вторым способом размещения службы WCF является размещение этой службы в контексте приложения Windows. Такой способ размещения называетсяавторазмещением (self-hosting). При авторазмещении служба может быть запущена в контексте любого приложения, будь то консольное приложение, приложение WinForms, приложение WPF или сервис Windows.
 Например, размещение службы как Windows-сервис дает возможность управлять запуском и остановкой этой службы, как через командную строку так и через оснастку Service Control Management, а так же настраивать возможные варианты действий при успешном или неудачном запуске. Более того, при нужной настройке служба будет автоматически запускаться при старте ОС. Если же служба будет размещена в Windows-приложении, то для ее старта необходимо будет так же запустить и само приложение (а так же нужно будет контролировать старт этого приложения при каждой перезагрузке системы). К тому же не всегда удобно, при входе на сервер видеть запущенные окна различных приложений, в контексте которых размещены службы WCF.
Но с другой стороны, в зависимости от функций службы WCF, размещение внутри Windows-приложения может быть единственным вариантом. Примером таких служб могут быть службы, работающие как узлы пиринговой сети, либо службы постоянно прослушивающие определенный адрес, на который клиенты отправляют сообщения.
В этой статье помимо самого способа размещения службы WCF я остановлюсь более детально и на самом процессе ее создания (чего я не сделал в первой статье). Для примера я создам WCF службу, которая может быть запущена как сервис ОС или как консольное приложение.
Создадим в Visual Studio новое консольное приложение (New->Project->Console Application). Я назвал его WcfHosting
Первым делом реализуем сам WCF-сервис внутри нашего консольного приложения:
1. Добавим в проект новый класс и назовем его WcfService.cs


В этом классе будет реализован процесс запуска и остановки нашей службы WCF. Так же здесь я реализую интерфейс методов (в терминологии WCF - контракт), которыми будет обладать наша служба, а так же их реализацию в производном классе.


Для того, чтобы начать работать с объектной моделью WCF нужно добавить в наш проект ссылку на сборку System.SeviceModel. Именно в пространстве имен этой сборки находятся методы создания и управления WCF-сервисами.


2. На втором шаге реализуем интерфейс методов (контракт) WCF-службы в файле WcfService.cs. В интерфейсе мы просто декларируем список всех методов, которыми будет обладать наша служба. Я назвал интерфейс IMyWcfService. В нем я определяю всего один метод GetDate(), который будет возвращать стоку текущей даты.
[ServiceContract]
public interface IMyWcfService
{
   [OperationContract]
   string GetDate();
}



Обратите внимание на атрибуты ServiceContract и OperationContract. WCFреализует свой функционал через контракты. Суть контракта WCF, как и суть обычного контракта из нашей повседневной жизни, заключается в определении, что будет делать наш сервис, какими возможностями он будет обладать. Для WCF контракт - это обычный интерфейс, в котором описаны все методы этой службы. Для того чтобы служба знала, что какой-либо интерфейс является контрактом, перед ним ставится атрибут ServiceContract (контракт о службе), а, соответственно, перед каждым его методом ставится атрибут OperationContract(контракт об операции).


Как только мы объявили контракт службы, осталось только его реализовать. Для этого нужно создать класс, производный от контракта и реализовать все его методы:

public class MyWcfService : IMyWcfService
{

   #region IMyWcfService Members

   public string GetDate()
   {
      return DateTime.Now.ToString();
   }

   #endregion
}

3. Теперь все готово для реализации самой WCF-службы. В файле WcfService.cs создадим новый класс WcfService. Этот класс будет отвечать за создание, запуск и остановку службы WCF. Данный класс я реализовал на основе шаблона проектирования Singleton. Более подробно с шаблонами проектирования, можно ознакомиться по этой ссылке: http://msdn.microsoft.com/ru-ru/windows/gg543141.
Почему Singleton? Суть выбора в том, что чтобы не усложнять наше приложение я буду размещать только одну службу, доступную по определенному адресу. Используя этот шаблон, я на объектном уровне ограничиваю возможность создания нескольких экземпляров класса службы и тем самым гарантирую, что в рамках приложения будет работать только одна служба WCF. (На самом деле существует возможность разместить несколько служб WCF в контексте одного приложения, но тогда для каждй службы в отдельности нужно на программном уровне прописывать адреса доступа и их оконечные точки)
/*
     * Класс реализации запуска WCF-сервиса. 
     * Реализован с использованием шаблона Singleton
     */

public sealed class WcfService
{
   private static WcfService _WcfService;
   private ServiceHost _SvcHost;

   public static WcfService Service
   {
      get
      {
         _WcfService = _WcfService ?? new WcfService();
         return _WcfService;
      }
   }

   // Конструктор по умолчанию определяется как private
   private WcfService()
   {
      // Регистрация сервиса и его метаданных
      _SvcHost = new ServiceHost(typeof(MyWcfService));
   }

   public void Start()
   {
      _SvcHost.Open();
   }

   public void Stop()
   {
      _SvcHost.Close();
   }
}


Класс содержит статический закрытый член экземпляра этого же класса, а так же свойство, при обращении к которому происходит проверка закрытого члена _WcfService и в случае, если он не определен - происходит вызов конструктора. Сам конструктор тоже является закрытым. Это гарантирует невозможность создания объекта нашего класса извне.
Вторым закрытым членом является переменная _SvcHost с типом ServiceHost. Это и есть наша служба WCF. В закрытом конструкторе происходит создание рабочего экземпляра службы. Обратите внимание, что в конструктор мы передаем контракт, тем самым сообщая службе, что она должна предоставлять для клиентов методы этого контракта.
Так же класс службы содержит два метода: Start() - запуск WCF службы и Stop() - ее остановка. Вот и все, класс службы реализован.
4. Последним шагом создания WCF-службы является определение базового адреса, по которому она будет доступна и оконечных точек (endpoints), то есть каналов, по которым мы можем доступиться к службе. Все эти настройки я вынес в конфигурационный файл. Использование настроек в конфигурационном файле делает сервис намного гибче и масштабируемей (не нужна перекомпиляция программы при каждом изменении настроек).
Добавим в наш проект файл конфигурации app.config. Следующий листинг показывает определение настроек службы WCF в конфигурационном файле:

  
    
      
        
          
            
          
        
        
        
      
    
    
      
        
          
        
      
    
  



При запуске служба просматривает конфигурационный файл приложенияapp.config (web.config) и ищет тег system.serviceModel. В этом теге определяются следующие настройки:
  • Тег service  определяет имя службы (пространство имен и имя контракта), а так же имя так называемой конфигурации поведения службы. Ниже в настройках присутствует тег behaviors. На самом деле, в этом теге имеется масса интересных настроек поведения служб WCF, о которых лучше подробно поговорить в отдельной статье. Здесь же я использую этот тег в конфигурации только для того, чтобы включить в нашу службу описание ее методов, что позволяет получать полную информацию о службе WCF клиентскому приложению (стандартное описание на языке WSDL). 
  • Тег host содержит список базовых адресов службы. Я определяю адрес на основе протокола http для доступа к методам службы
  • Далее определяются теги оконечных точек (endpoints). Обратите внимание - я определил две точки. Первая точка использует привязку basicHttpBinding и контракт WcfHosting.IMyWcfService. А вторая точка используется для получения описания службы (о чем говорилось выше). Такая точка называется точка обмена метаданными (mex). Она имеет жестко заданные в объектной модели WCF адрес mex (это относительный адрес от базового, определенного в теге host), привязку (mexHttpBinding) и контракт (IMetadataExchange). Наличие такой точки в службе позволяет клиенту получить подробное описание всех методов службы, их типов и возвращаемых значений. Среда Visual Studio позволяет очень легко получить описание службы через эту точку. Ниже я приведу пример как это можно сделать.
Все, наша служба полностью готова. Теперь остается только ее разместить внутри нашего консольного приложения. Как я ранее уже писал, консольное приложение будет иметь возможность простого запуска, а так же может быть установлено как сервис ОС Windows. Для того, чтобы наше приложение могло быть установлено и запущено как сервис ОС, в проект нужно добавить элемент WindwosService. Я назвал его WinService.cs.
Класс WinService наследуется от родительского класса ServiceBase и имеет дваoverride-метода OnStart и OnStop. Первый срабатывает, когда сервис стартует, второй - когда останавливается. Определим в классе закрытый член нашей службы WCF. В методе OnStart пропишем запуске WCF-службы, в OnStop - ее остановке:

partial class WinService : ServiceBase
{
   private WcfService _Wcf;

   public WinService()
   {
      InitializeComponent();
   }

   protected override void OnStart(string[] args)
   {
      try
      {
          _Wcf = WcfService.Service;
          _Wcf.Start();
      }
      catch (Exception ex)
      {
          EventLog.WriteEntry(ex.Message,   System.Diagnostics.EventLogEntryType.Information);
      }
    }

    protected override void OnStop()
    {
       if (_Wcf != null)
       { _Wcf.Stop(); }
    }
}

Код сервиса готов! Теперь определим установщик для сервиса Windows. Самый простой способ это следать - это кликнуть по элементу WinService и в окне пустого дизайнера открыть правой кнопкой мыши контекстное меню и выбрать пункт Add Installer.
Это автоматически добавит в проект файл ProjectInstaller.cs. В дизайнере этого файла будут определены два элемента: Service (содержит имя сервиса, его описание, а так же режим запуска) и Process (процесс, в контексте которого будет запущен сервис). Переименуйте их как вам будет угодно и в свойствах Service укажите имя, описание и тип запуска сервиса.
Последний этап - реализуем запуск WCF-службы в режиме консоли и в режиме сервиса Windows. Откроем в проекте файл Program.cs и напишем следующий код:
static void Main(string[] args)
{
   // Если запускает пользователь сам
   if (Environment.UserInteractive)
   {
      WcfService s = WcfService.Service;
      s.Start();

      while (Console.ReadLine().ToLower() != "exit") { }
      s.Stop();
      return;
   }
   else
   {
     ServiceBase[] ServicesToRun;
     ServicesToRun = new ServiceBase[] { new WinService() };
     ServiceBase.Run(ServicesToRun);
   }
}


При запуске программы пользователем (проверяем переменную Environment.UserInteractive) мы вызываем наш Singleton-класс, где реализована служба WCF и вызываем метод Start(). В случае же запуска приложения в контексте сервиса Windows  мы вызываем метод Run класса ServiceBase. 
Все! Чтобы сервис появился в оснастке Service Control Management воспользуйтесь утилитой InstallUtil, входящей в пакет .NET SDK utility. С помощью этой утилиты можно установить/удалить любой сервис в оснастку Service Control Management.
В итоге мы получили следующее: WCF-служба размещена в контексте консольного приложения и сервиса ОС, доступна по адресу http://localhost:9000/WcfHosting, а ее описание доступно по адресу http://localhost:9000/WcfHosting/mex. Служба работает через протокол http.
Обратиться к службе очень просто. Для этого в любом проекте Visual Studio кликните правой кнопкой мыши по элементу Service Reference и выберите пунктAdd Service Reference.

В открывшемся окне введите http://localhost:9000/WcfHosting/mex и нажмите Go:
Итак, среда Visual Studio видит службу WCF, а так же все ее методы. Это все доступно, благодаря оконечной точке mex, о которой я писал выше. Укажите название пространство имен (я указал WcfServiceReference) и нажмите на кнопку Ок. Visual Studio создаст класс-обертку для методов службы, и вызвать метод станет проще простого:
WcfServiceReference.MyWcfServiceClient wcf = 
  new WcfHosting.WcfServiceReference.MyWcfServiceClient();
wcf.Open();
string date = wcf.GetDate();
wcf.Close();

Способы размещения служб WCF. Часть 1: размещение службы в IIS


Финальной точкой при разработке любой WCF-службы является вопрос о том, как и где разместить эту службу. Под размещением понимается запуск службы в контексте какого-либо процесса операционной системы. Такой процесс называется владельцем этой службы. Он отвечает за время жизни службы и предоставляет контекст доступа к ее методам. 
При выборе способа размещения службы нужно руководствоваться следующими важными факторами:
  • возможность быстрого включения/остановки службы
  • удобство администрирования
  • использование различных протоколов взаимодействия: tcp, http и т.д.
Существуют следующие способы размещения WCF-служб:
  • Размещение службы в среде IIS
  • Размещение в контексте любого Windows-приложения (сервис операционной системы, консольное приложение, WinForm-приложение и т.д.).
  • Размещение в среде Windows Process Activations Services (WAS)
Размещение службы WCF в IIS
Начнем с самого простого и быстрого способа размещения службы -  размещения в среде IIS. В IIS версии 6 для управления процессами корпорацией Microsoft были реализованы пулы приложений, за счет которых происходила четкая изоляция одного запущенного приложения от другого. Это значительно увеличило надежность работы приложений их доступность и безопасность, а так же дало возможность гибкой настройки их конфигурации.
Но, несмотря на все эти улучшения, размещение WCF-службы в IIS 6 дает одно очень значимое ограничение: IIS 6 может работать только по протоколу HTTP, следовательно, если ваша служба реализована через привязку (binding), не использующую протокол HTTP, например, привязка NetTcpBinding, то размещение службы на IIS будет невозможно.
Корпорация Microsoft учла эту ситуацию в релизах IIS 7.0 и IIS 7.5. Нет, разработчики, конечно же, не изменили в IIS стек протоколов. На самом деле было просто обобщено управление процессами и разделено согласно протоколам между IIS и новой службой Windows Process Activations Services (WAS), о которой речь пойдет в следующей части.
Плюсы размещения службы в IIS:
  • Интеграция IIS с инфраструктурой сервера, что обеспечивает высокую производительность
  • Удобство управления службой через графическую оболочку IIS
  • Встроенная безопасность в IIS.
Минусы размещения службы в IIS:
  • Служба должна использовать только привязку на основе протокола HTTP (BasicHttpBinding или WSHttpBinding)
  • Невозможность предоставления специального административного интерфейса управления службой отличного от интерфейса IIS
Таким образом, если поставлена цель разместить службу WCF в среде IIS, то в качестве одной из доступных привязок нужно использовать BasicHttpBinding илиWSHttpBinding.
Для примера я буду размещать службу, созданную по стандартному шаблону в Visual Studio 2010 (меню New->Project->WCF Service Application). Чтобы разместить службу WCF в IIS нужно сделать следующее:
1. Создать виртуальный каталог (здесь и далее я буду использовать IIS 7.5)
Я назвал сайт wcfhost. В IIS 7.5 для каждого нового сайта автоматически создается отдельный пул приложения. В поле Physical path нужно указать путь к каталогу, где располагается служба WCF. В разделе Binding я указываю, что к сайту можно будет обратиться по адресу типа http://ServerName:8096, где ServerName - имя сервера, где установлен IIS.
2. Подготовить файл с расширением *.svc, в котором определяется месторасположение службы. При использовании стандартного шаблона создания службы WCF в Visual Studio 2010 этот файл будет создан автоматически. В моем проекте он называется Service1.svc. Данный файл содержит все лишь одну строку:
<%@ServiceHost Language="C#" Debug="true" Service="WcfService1.Sevice1" CodeBehind="Service1.svc.cs"%>
Видно, что в файле указано пространство имен и имя класса сервиса, а так же имя файла кода.
3.  Внести необходимые настройки в web.config, а именно - определить оконечную точку (точки) (endpoints). Нужно не забывать, что  стек каналов в привязке должен использовать HTTP в качестве транспортного протокола. В WCF уже встроены две таких привязки: basicHttpBinding и wsHttpBinding. Определим привязку в разделеsystem.serviceModel:


   
     
       
     
   
   
   
 

Здесь мы определили, что наша служба будет размещена по адресу http://host:8096 и иметь две оконечные точки: точка с привязкой basicHttpBinding (заметьте, что адрес у точке пустой, следовательно, сервис будет использовать для этой точки адрес, указанный в теге baseAddress) и точка с привязкой mexHttpBinding (эта точка служит для получения метаданных по сервису, а именно описание его интерфейса и методов)  
Вот и все, что нужно для размещения на сервере IIS. Теперь откомпилируем наш проект в Visual Studio  и скопируем его содержимое в виртуальный каталог IIS. 
Далее обратимся к нашему сервису по следующему адресу http://host:8096/service1.svc. В результате получим стандартное окно WCF-службы.
Все, служба доступна. Теперь любой клиент, может обращаться к указанному адресу http://host:8096/service1.svc и вызывать методы сервиса.
Замечание: хочу упомянуть один момент: если вы, компилируя сервис в VisualStudio, указали target platform - x86, то у вас может возникнуть ошибка при обращении к сервису, связанная с тем, что IIS на сервере работает в режиме x64. Для решения достаточно просто выбрать target platform - x64 или Any CPU, скомпилировать приложение и скопировать его на IIS.

среда, 7 апреля 2010 г.

Create md5 hash-code using assemblies in SQL Server 2005

It's very simple create md5 hash function in such languages like C# or VB.Net. But in some cases it's nessesary to implement md5-hash algorithm on SQL Server. Unfortunally, SQL Server does not have hash function like md5 and writing T-SQL script is not good idea too. Performance of such script will be very low.

One way to solve this problem is to create .net assembly and attach it to SQL Server instance. Ok, let's do it step by step:

1. Create new project in visual studio. Choose class library template, enter project name and click Ok.

2. Write function that implement md5 hash-code. For this purpose you need add assembly "System.Security.Cryptography" in your project. Listing below show md5 function.
using System.Security.Cryptography;
using System.Text;
using System.Data;
using System.Data.SqlTypes;
namespace Md5Hash
{
  public class Md5Class 
  {
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void HashString(SqlString value, out SqlString result)
    {
      string str = value.ToString().Trim();
      HashAlgorithm mhash = mhash = new MD5CryptoServiceProvider();
      byte[] bytValue = System.Text.Encoding.UTF8.GetBytes(str);
      byte[] bytHash = mhash.ComputeHash(bytValue);
      mhash.Clear();
        
      StringBuilder sBuilder = new StringBuilder();
      // Loop through each byte of the hashed data 
      // and format each one as a hexadecimal string.
      for (int i = 0; i < bytHash.Length; i++)
      {
         sBuilder.Append(bytHash[i].ToString("x2"));
      }
      // Return the hexadecimal string.
      result = sBuilder.ToString();
    }
  }
}
If you want to use your assembly methods over SQL Server stored procedures, you should folow by next rules:
   - your methods must be implemented as a public static methods on a class in your assembly;
   - your methods must be declared as void or return integer value (in my example I declare method as void);
   - number of parameters must be the same as in stored procedures
   - all parameters must be declared according to SQL Server data types (see MSDN article http://msdn.microsoft.com/en-us/library/ms131092(v=SQL.90).aspx)

Let's back to out listing. We have class called "MD5Hash". This class have only one method "HashString" marked with attribute [Microsoft.SqlServer.Server.SqlProcedure].  By this atribute we define that out method will be used like a stored procedure.
Method "HashString" takes two arguments:
  • value - SqlString data type parameter which hash-code we need to return
  • result - SqlString pass-by-reference data type parameter which stored procedure returning through an OUTPUt argument
Build our project.

3. Now we should create stored procedure on the SQL Serve side. For using assemblies in T-SQL we must create assembly object in SQL Server database. The folowing example shows how to do it:

create assembly a_md5Hash
from '\\server\SolutionFolder\bin\Debug\MD5Hash.dll'
go

This SQL-statement create sql assembly based on out .net class libraly. Next step is to create stored procedure which will use our assembly

create procedure dbo.sp_md5Hash (@value nvarchar(20), @return nvarchar(max) output)
as external name a_md5hash.[Md5Hash.Md5Class].HashString

Argument as external name assembly_name.class_name.method_name specifies the method of a .Net Framefork assembly for a CLR stored procedure to reference. Parameters:
  1. assembly_name is a name of our SQL Server assembly object. 
  2. class_name is a namespace and class name of our .net library
  3. method_name is a name of md5 class method in .net library
4. Ok. We have done it! Let's try to get hash-code over our stored procedure:

declare @res nvarchar(max)
exec dbo.sp_md5Hash 'Hello World!', @res output
select @res

Well I've got 86fb269d190d2c85f6e0468ceca42a20. Good luck!

четверг, 21 января 2010 г.

Using unmanaged Dll libraries and setting default dll directory for .NET application


Sometimes it's necessary to call Windows API functions or some custom functions from DLL libraries (not assemblies) in .Net applications (C# or VB.net). For example, we have DLL library created in Visual C++ or Delphi. So, how can we call functions in this library?First of all we need add references on this libraries to our project? Using menu "Add references" is not good idea because it works only with .net assemblies. If you try to add reference on this dll library you've got next error message:


To solve this problem you shoud use DllImport attribute in your project. Let's try to call MessageBox API function from user32.dll library by using DllImport attribute.
I will show this example by using C# console application.

Firstly import namespace System.Runtime.InteropServices. And then add attribute DllImport in class declaration with name of dll library. Parameter CallingConvention define default convention for calling unmanaged function with platform invoke.


using System;
using System.Runtime.InteropServices;

namespace test
{
class Program
{
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern int MessageBox(System.IntPtr hWnd, String lpText, String lpCaption, System.UInt32 uType);

static void Main(string[] args)
{
MessageBox(System.IntPtr.Zero, "Test", "Text", 0);
}
}
}

After attribute DllImport I declare WinAPI function MessageBox. Prototype of this function you can find in MSDN. It's important to mark all unmanaged dll function with keywords static and extern.

Run this project and you will see standard windows dialog message box.

Now let's consider next situation: for example you have your own dll library and you want to distribute this library with application.

So, there is two ways: you should add this library into root of project or add special folder to project and add file there. Don't forget to mark library as content:

Well, now if you bild your project dll library will copy to output directory. But there is some problem. If you library located in subfolder (for examle, in folder called "Dlls") of your project when you try to call some dll functions you have got error message "Cannot find dll library".

To solve this problem you need to set dll directory path. For this purpose let's try to use WinAPI function SetDllDirectory. This function add directory to the search path used to locate DLLs for your application.

After calling SetDllDirectory, the DLL search path is:
  1. The directory from which the application loaded.
  2. The directory specified by the lpPathName parameter.
  3. The system directory. The name of this directory is System32.
  4. The 16-bit system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
  5. The Windows directory.
  6. The directories that are listed in the PATH environment variable.
I use this function in Load event of my project.

public partial class MyForm : Form
{
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern bool SetDllDirectory(String lpPathName);

private void MyForm_Load(object sender, EventArgs e)
{
// Restores the default search order
SetDllDirectory(null);

// Add dll directory path
SetDllDirectory(AppDomain.CurrentDomain.BaseDirectory + "Dlls");

// Some code here
}
}

First line restore default search paths of application and second line add new path for dll directory.
It's very useful to store dll libraries in separate folder. Is help to structure files in project correctly and always find needed library very quickly.