Типы повторного использования в текущей сборке для прокси WCF

VS WCF-интеграция имеет приятный вариант "Типы повторного использования в проверенных сборках". Проблема в том, что мне нужно то же самое, но для текущей сборки. Некоторые из типов уже определены в моей сборке, и мне нужно их повторно использовать.

Сценарий использования:

  • У меня есть сборка, и здесь есть TypeA.
  • Я добавляю Service Reference, и один из методов возвращает тип, полностью совместимый с TypeA (свойства, имя).
  • Добавить Service Reference генерирует прокси-сервер, но он воссоздает новый TypeA внутри.

На шаге 3 мне нужен прокси-сервер, который вернет TypeA. Не новый TypeA.

Ответ 1

Если я понимаю, что вы хотите сделать, то это сценарий, с которым я обычно сталкиваюсь, и хорошо, WCF имеет достойный ответ: просто не используйте SvcUtil/WS Service Reference wizards.

Если у вас есть большинство классов контрактов, уже определенных на вашей стороне клиента (будь то, потому что у вас есть общая сборка или у вас есть эквивалентные классы, определенные в вашем проекте), вы можете просто перейти к следующему шагу и либо импортировать полный контракт на обслуживание в виде кода или просто переопределить его на стороне клиента.

Нет ничего, что заставило бы вас использовать svcutil и друзей, просто определите свой интерфейс и либо напрямую используйте модель канала (например, ChannelFactory <T> и друзья), либо, если вы предпочитаете использовать прокси-классы, просто создайте свой собственный ClientBase <T> -пределенный класс. Это действительно очень легко, и это сэкономит вам неприятности в долгосрочной перспективе.

Ответ 2

Существует простой способ совместного использования типов между клиентом и сервисом, просто добавив ссылку на сборку общего типа к вашему клиенту ПЕРЕД добавлением служебной ссылки.

Здесь вы можете найти подробный сценарий и образец проекта:

http://blog.walteralmeida.com/2010/08/wcf-tips-and-tricks-share-types-between-server-and-client.html

Ответ 3

У меня была такая же проблема, и я хотел, чтобы тестовая проводка указывала на пару сервисов. Каждая служба будет иметь общие данные.

Что нужно сделать:

  • Используйте svcutil с /t: метаданные на каждом URL-адресе.
  • Переименуйте все сгенерированные файлы с чем-то уникальным для службы (например, переименуйте lala.xsd в 1_lala.xsd)
  • Скопировать все сгенерированные файлы в одно место
  • Используйте svcutil с *.xsd.wsdl/out:output.cs/namespace:, MySpecialNamespace, чтобы сгенерировать ВСЕ контракты на обслуживание и datacontracts в один файл.

Если вы хотите быть хитрым: используйте следующий шаблон T4:

<#@ template language="C#v4.0" hostspecific="True"#>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.IO" #>
<#=GetGeneratedCode(
"http://localhost/Service/Service1.svc",
"http://localhost/Service/Service2.svc",
"http://localhost/Service/Service3.svc",
"http://localhost/Service/Service4.svc"
)#>
<#+
const string _svcutil = @"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\svcutil.exe";

private string GetGeneratedCode(params string[] urls)
{
    var tmp = GetTemporaryDirectory();
    foreach (var url in urls)
    {
        GetMetadata(url, tmp);
    }

    RunSvcutil(tmp, "*.wsdl *.xsd /out:output.cs /namespace:*," +     Path.GetFileNameWithoutExtension(Host.TemplateFile));
    var result = File.ReadAllText(Path.Combine(tmp, "output.cs"));
    return result;
}

private static void RunSvcutil(string workingFolder, string arguments)
{
    var processInfo = new ProcessStartInfo(_svcutil);
    processInfo.Arguments = arguments;
    processInfo.WorkingDirectory = workingFolder;

    var p = Process.Start(processInfo);
    p.WaitForExit();
}

private static void GetMetadata(string url, string destination)
{
    var workingFolder = GetTemporaryDirectory();
    RunSvcutil(workingFolder, string.Format("/t:metadata \"{0}\"", url));

    foreach (var filename in Directory.GetFiles(workingFolder))
    {
        File.Copy(filename, Path.Combine(destination,     Path.GetFileNameWithoutExtension(url) + "_" +  Path.GetFileName(filename)));
    }
}

private static string GetTemporaryDirectory()
{
    string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
    Directory.CreateDirectory(tempDirectory);
    return tempDirectory;
}
#>