Подтвердить что ты не робот

Сгенерировать серверную службу WCF автоматически из существующего API

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

Например, допустим, что у меня есть следующий

public interface RainfallMonitor
{
    [ExposeToWeb]
    void RecordRainfall(string county, float rainfallInches);

    [ExposeToWeb]
    float GetTotalRainfall(string county);

    void ClearRainfall(string county);
}

Я понимаю, что я мог бы создать библиотеку сервиса WCF, как обычно, и просто добавить службу WCF под названием "RainfallMonitor".

То, что я изучаю, - это... возможно/разумно каким-то образом генерировать весь код, связанный с WCF, во время компиляции для всего API без фактического создания классов WCF-сервисов. Возможно использование атрибутов, таких как ExposeToWeb, чтобы указать, какие методы выставлять через службы. Результат будет работать следующим образом:

  • Создание/изменение классов в проекте под названием RainfallAPI
  • Скомпилируйте и создайте другой проект /dll, созданный с именем RainfallService автоматически.

По существу:

  • Если это возможно, какой подход я мог бы предпринять, чтобы реально реализовать Это?
  • Какие серьезные подводные камни я мог бы натолкнуться?
  • Есть ли какая-то существующая база кода, которая делает что-то подобное, я мог бы изучить вдохновение.

Для уточнения: я не спрашиваю об автоматической генерации заглушки клиента, я спрашиваю о создании служб на стороне сервера.

4b9b3361

Ответ 1

Недавно я возглавил эту библиотеку: Fody. Насколько я понимаю, это позволяет подключаться к процессу сборки и вводить IL в сборку. Я не совсем уверен, как это работает, но может быть возможно выполнить поиск по IL, найти все методы с атрибутом ExposeToWeb и использовать это, чтобы передать контракт для службы WCF в сборку.

Но, с другой стороны, если вы уже добавляете атрибуты в класс, почему бы просто не добавить правильные атрибуты WFC для начала, а затем использовать SvcUtil для создания контрактов в пост-сборке?

EDIT: Ниже приведен пример использования SvcUtil:

С#:

[ServiceContract]
public interface IRainfallMonitor
{
    [OperationContract]
    void RecordRainfall(string county, float rainfallInches);
}

public class RainfallMonitor : IRainfallMonitor
{
    public void RecordRainfall(string county, float rainfallInches)
    {
        // code
    }
}

Создать сборку PowerShell:

$svcutil = "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools\SvcUtil.exe"
$csc = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe"
$assembly = "bin/debug/ProjectWithoutWCF.dll"
$service = "ProjectWithoutWCF.RainfallMonitor"
$outputns = "ProjectWithoutWCF.RainfallMonitor.Service"
$outputdir = "bin/debug"

md svcutil_tmp
cd svcutil_tmp

& $svcutil /serviceName:"$service" "../$assembly"
& $svcutil *.wsdl *.xsd /importxmltypes /out:"output.cs" /n:"*,$outputns"
& $csc /target:library /out:$outputns.dll "output.cs"

cp "$outputns.dll" "../$outputdir"
cp output.config "../$outputdir/$outputns.dll.config"
cd ..
rm -r .\svcutil_tmp

и вам понадобится что-то подобное в конфигурации проекта:

<system.serviceModel>
  <services>
    <service name="ProjectWithoutWCF.RainfallMonitor" >
      <endpoint address="" binding="basicHttpBinding" contract="ProjectWithoutWCF.IRainfallMonitor">
      </endpoint>
    </service>
  </services>
</system.serviceModel>

Немного неудобно, и вам, скорее всего, понадобится некоторая настройка на script и конфиг. Но в результате у вас есть файл ProjectWithoutWCF.RainfallMonitor.Service.dll с контрактами службы WCF.

Ответ 2

В отношении вашего вопроса "Что я изучаю... возможно ли/разумно каким-то образом генерировать весь код, связанный с WCF, во время компиляции для всего API без фактического создания классов WCF-сервисов". варианты, но все они будут выполнять много работы.

Вам нужно будет написать приложение/библиотеку генерации кода, в которой используются классы, такие как CSharpCodeProvider (есть и для VB) и отражение, чтобы проверить вашу библиотеку как шаг пост-сборки, построить код, который вы хотите в памяти, и сохранить его как DLL.

Это приложение должно будет найти созданный вами настраиваемый атрибут, который указывает, что он должен быть сервисом WCF, и выводить код WCF на основе правил, которые вы определяете.

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

Имейте в виду, что, используя модель CodeDOM, вы можете преодолеть некоторые проблемы, о которых упоминалось выше, например, требующие сериализации для контрактов данных. Это может быть добавлено, и новая библиотека DLL будет выводиться вашей библиотекой отражения на основе CodeDOM.

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

Ответ 3

Да, это можно сделать с умеренным усилием, используя нужные инструменты. Если у вас есть Visual Studio, у вас уже есть генератор кода Microsoft T4. Он позволяет сгенерировать код, написав "текстовые шаблоны", которые очень напоминают синтаксис ASP.NET RAZOR. Используя T4, вы можете фактически создавать свои существующие классы и использовать рефлексию для чтения всех имен классов и сигнатур методов и в конечном итоге генерировать ваши службы WCF. Это не так сложно!

Здесь образец шаблона T4 из Учебник Олега Сыча:

<#@ template language="C#v3.5" #>
<#@ output extension="SQL" #>
<#@ assembly name="Microsoft.SqlServer.ConnectionInfo" #>
<#@ assembly name="Microsoft.SqlServer.Smo" #>
<#@ import namespace="Microsoft.SqlServer.Management.Smo" #>
<#
    Server server = new Server();
    Database database = new Database(server, "Northwind");
    Table table = new Table(database, "Products");
    table.Refresh();
#>
create procedure <#= table.Name #>_Delete
<#
    PushIndent("\t");
    foreach (Column column in table.Columns)
    {
        if (column.InPrimaryKey)
            WriteLine("@" + column.Name + " " + column.DataType.Name);
    }
    PopIndent();
#>
as
    delete from <#= table.Name #>
    where
<#
    PushIndent("\t\t");
    foreach (Column column in table.Columns)
    {
        if (column.InPrimaryKey)
            WriteLine(column.Name + " = @" + column.Name);
    }
    PopIndent();
#>

Результат будет выглядеть так:

create procedure Products_Delete
    @ProductID int
as
    delete from Products
    where ProductID = @ProductID

Конечно, ваш пример, вы бы использовали отражение в своей существующей библиотеке классов вместо sql-запросов. Службы WCf, которые вы создаете, могут просто вызвать вашу существующую библиотеку, чтобы вам не пришлось копировать всю фактическую логику домена.

MSDN

https://msdn.microsoft.com/en-us/library/bb126445.aspx

Ответ 4

Вы можете использовать Roslyn, Roslyn - новый компилятор в качестве сервиса, где вы можете анализировать файл С# и генерировать исходный код по мере необходимости.

Здесь вы можете увидеть несколько примеров,

http://www.codeproject.com/Articles/302595/Roslyn-CTP-Three-Introductory-Projects

Это не должно быть так сложно.