Суть вопроса
В большинстве случаев .NET-приложения являются платформонезависимыми. Мы ожидаем, что наше приложение будет одинаково выполняться как в 32-хразрядной ОС, так и 64-хразрядной.
Так обычно и происходит до тех пор, пока нам не понадобится использовать внешние платформозависимые библиотеки, например неуправляемые. Если такая библиотека существует в вариантах и для x86
, и для x64
, то это может принести нам определенную головную боль. Будем исходить из того, что ограничивать наше приложение, например, только 32-хразрядным процессом не в наших правилах.
Возможно, нам придется поддерживать вдвое больше конфигураций проекта. В этом случае при отладке придется переключать конфигурации, ведь разработческий веб-сервер Cassini существует только в x86
варианте, а ReSharper может запускать тесты и в 64-хразрядном процессе. Кроме того, придется выпускать два дистрибутива и предоставлять пользователю при скачивании с сайта ох какой нелегкий выбор. Поэтому разумным решением выглядит выбор подходящей для работы библиотеки уже в runtime в зависимости от того, в каком процессе (32-х или 64-хразрядном) код выполняется. При этом сами проекты остаются AnyCPU
.
В нашем приложении необходимо подключаться к к Oracle Database, для чего используются библиотеки Oracle Instant Client и Oracle Data Provider for .NET.
Решение
Решение было найдено в виде тега runtime/assemblyBinding
конфигурационного файла приложения. В app.config
добавляем следующее:
<configuration> <!-- Выбор версии библиотеки ODP.NET в зависимости от Runtime архитектуры --> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="Oracle.DataAccess" publicKeyToken="89b483f429c47342" culture="neutral" processorArchitecture="x86" /> <codeBase version="4.112.2.0" href=".\x86\Oracle.DataAccess.dll"/> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="Oracle.DataAccess" publicKeyToken="89b483f429c47342" culture="neutral" processorArchitecture="amd64" /> <codeBase version="4.112.2.0" href=".\x64\Oracle.DataAccess.dll"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>
У атрибута processorArchitecture
четыре возможных значения: x86
, amd64
, msil
, ia64
. Пути в codeBase
могут отличаться в зависимости от типа проекта (например, для ASP.NET должно быть href=".\bin\x64\Oracle.DataAccess.dll"
).
Ну а для того чтобы библиотеки оказались в нужных папках, в файлы «исполняемых» проектов (тестовые сборки, веб-сервисы и сайты, и истинно исполняемые приложения .exe
) после строки
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
добавляется включение собственных целей MSBuild:
<Import Project="$(MSBuildProjectDirectory)\..\CommonItems.targets" />
В файле проекта обычно есть закомментированная цель AfterBuild
. Ее необходимо раскомментировать/добавить/отредактировать:
<Target Name="AfterBuild" DependsOnTargets="CopyDataAccessFiles" >
Файл CommonItems.targets
содержит описание этих общих элементов для исполняемых проектов. Здесь определена цель по копированию зависимостей:
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <OracleICFilesx86 Include="$(MSBuildProjectDirectory)\..\externals\OracleIC\x86\*.dll"> <Visible>False</Visible> </OracleICFilesx86> <OracleICFilesx64 Include="$(MSBuildProjectDirectory)\..\externals\OracleIC\x64\*.dll"> <Visible>False</Visible> </OracleICFilesx64> <OdpNetFilesx86 Include="$(MSBuildProjectDirectory)\..\externals\Odp.Net\x86\*.dll"> <Visible>False</Visible> </OdpNetFilesx86> <OdpNetFilesx64 Include="$(MSBuildProjectDirectory)\..\externals\Odp.Net\x64\*.dll"> <Visible>False</Visible> </OdpNetFilesx64> </ItemGroup> <Target Name="CopyDataAccessFiles" > <Copy SourceFiles="@(OracleICFilesX86);@(OdpNetFilesx86)" DestinationFolder="$(MSBuildProjectDirectory)\$(OutputPath)\x86\" SkipUnchangedFiles="true" UseHardLinkIfPossible="true" /> <Copy SourceFiles="@(OracleICFilesX64);@(OdpNetFilesx64)" DestinationFolder="$(MSBuildProjectDirectory)\$(OutputPath)\x64\" SkipUnchangedFiles="true" UseHardLinkIfPossible="true" /> </Target> </Project>
Ограничения
У предложенного способа есть ограничения:
- Предполагается, что мы не используем типы управляемой платформозависимой библиотеки и, таким образом, не нуждаемся в ссылке на сборку (Oracle.DataAccess.dll) в своем проекте. Т.е. от сборки зависимость есть, но неявная, динамическая.
- Теперь мы с собой в дистрибутиве «тащим» библиотеки для всех поддерживаемых платформ. Для OracleIC это более 100 МБ на платформу.
Ссылки
ссылка на оригинал статьи http://habrahabr.ru/post/165767/
Добавить комментарий