Советы по архитектуре для использования / упаковки большого веб-сервиса - PullRequest
2 голосов
/ 12 марта 2012

Я ищу хорошие практики для реализации умной архитектуры и способа интеграции с системой с множеством различных веб-сервисов wdsl.

Я занимаюсь хобби с C # уже 2 года, потому что я не всегда использую правильную терминологию, но я попытаюсь описать то, что я ищу.

Основная причина, по которой я публикую это, состоит в том, чтобы получить представление об областях, которые мне следует прочитать, о шаблонах проектирования для реализации и о том, как правильно управлять вызовами API.

Я интегрируюсь с системой, которая предлагает множество различных API. У каждого API есть 20-30 методов. Каждый API принимает несколько параметров в формате XML.

Чтобы дать вам представление, я взял в качестве примера следующий API-интерфейс: API-интерфейс DeviceManager и метод Create для создания устройства в системе. API принимает два параметра, строковый ключ и строку параметров XML.

Пример

DeviceManager

public string Create(string sKey, string sXmlParameters)  

**Parameters:**

Name: sKey Type: string  
Description: 
The API security key. A valid API security key is required for every API call.  

Name: sXmlParameters Type: string  
Description: Values needed to create a new device. See the Additional Information      >section for XML format.  

Return Value: Type: string  
Description: Returns XML containing the status of the creation and if the status is  
Constants.ExternalServiceReturnCodes.SUCCEEDED, the ID of the new device. 

XMLParameters:

<PARAMETERS>      
    <NAME>string - up to 64 characters. Non-blank name of the device. 
    Must be unique within a gateway.  
    </NAME>   
    <DESCRIPTION>string - up to 1024 characters. The description of the new device.
    </DESCRIPTION> (optional)  
    <TYPEID>string of DeviceType. The type of device. 
    </TYPEID>  
    <GATEWAYID>string - 32-character GUID. The ID of the gateway to associate with the 
    device. If this node is included, it must contain an ID of   
    a gateway that exists in the solution.  
    </GATEWAYID> (optional)  
    <INSTALLATIONDATETIME>  
    date time in UTC - greater than or equal to   
    1753-01-01 00:00:00.000 and less than or equal to   
    9999- 12-31 23:59:59.998. The date time that the device was installed.  
    </INSTALLATIONDATETIME> (optional - if not included, the installation   
                        date time is set to the date time in UTC when the device is 
                        created in the solution)       
    <SERIALNUMBER>string - up to 64 characters. The serial number of the device
    </SERIALNUMBER> 
    <TIMEZONEID>string - time zone ID. The time zone ID of the device.
    Call the TimeZoneManager.RetrieveList API to get a list of valid time zone IDs  
    </TIMEZONEID> (required for device type 'meter')  
    <HARDWAREVERSION>string - up to 32 characters. The hardware version of the device.  
    </HARDWAREVERSION> (optional)  
    <GEOGRAPHICCOORDINATES>  
        <LATITUDE>decimal - greater than or equal to -90 and less than or  
        equal to 90. The latitude geographical coordinate of the   
        device in decimal degrees. The value must be from the   
        WGS84 spatial reference system.                                                                       
        If more than 6 digits after the decimal point are included,   
        the value will be rounded to 6 digits.  
        </LATITUDE>  
        <LONGITUDE>  
        decimal - greater than or equal to -180 and less than or  
        equal to 180. The longitude geographical coordinate of the   
        device in decimal degrees. The value must be from the   
        WGS84 spatial reference system.
        If more than 6 digits after the decimal point are included,   
        the value will be rounded to 6 digits.  
        </LONGITUDE>  
    </GEOGRAPHICCOORDINATES> (optional)
    <METER>  
        <ID>string - 12 hexadecimal characters.</ID> 
        <TRANSFORMERID>string - up to 128 characters.</TRANSFORMERID>  
        <DOWNLIMIT>integer - greater than or equal to 0 and less than or                                                          
        equal to 65535. 
        </DOWNLIMIT> (optional)
    <METER>
</PARAMETERS> 

Формат возврата API:

<DEVICEID>string - 32-character GUID. The ID of the new device.</DEVICEID> 

API всегда возвращает данные в следующем формате:

<RETURNS> 
        <STATUS> 
                 String from Constants.ExternalServiceReturnCodes class. 
        </STATUS> 
        <APIPAYLOAD> 
                 Additional information from the API call. Node may be empty. For 
                 APIs that return information, that information will be shown in 
                 the Return section.
        </APIPAYLOAD> 
</RETURNS> 

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

<RETURNS> 
        <STATUS> 
                 SUCCEEDED
        </STATUS> 
        <APIPAYLOAD> 
                <DEVICEID>string - 32-character GUID. The ID of the new device.</DEVICEID> 
        </APIPAYLOAD> 
</RETURNS> 

На данный момент я работаю над созданием классов для всех XML-параметров, чтобы иметь возможность сериализовать и десериализовать параметры и полезные данные из API, но их определение требует очень много времени. Пример приведен ниже для создания параметров API и полезной нагрузки. (простой пример использования get set)

DeviceManager Создать параметры

[XmlRoot(ElementName = "PARAMETERS")]
public class Create
{

    [XmlElement(ElementName = "NAME")]
    public string Name { get; set; }

    [XmlElement(ElementName = "DESCRIPTION")]
    public string Description { get; set; }

    [XmlElement(ElementName = "TYPEID")]
    public string TypeId { get; set; }

    [XmlElement(ElementName = "GATEWAYID")]
    public string GatewayId { get; set; }

    [XmlElement(ElementName = "INSTALLATIONDATETIME")]
    public string InstallationDateTime { get; set; }

    [XmlElement(ElementName = "SERIALNUMBER")]
    public string SerialNumber { get; set; }

    [XmlElement(ElementName = "TIMEZONEID")]
    public string TimeZoneId { get; set; }

    [XmlElement(ElementName = "HARDWAREVERSION")]
    public string HardWareVersion { get; set; }

    [XmlElement(ElementName = "GEOGRAPHICCOORDINATES")]
    public CreateParametersGeoGraphicCoordinates GeographicCoordinates { get; set; }

    [XmlElement(ElementName = "METER")]
    public CreateMeter Meter { get; set; }
}

public class CreateMeter
{
    [XmlElement(ElementName = "NEURONID")]
    public string NeuronId { get; set; }

    [XmlElement(ElementName = "TRANSFORMERID")]
    public string TransformerId { get; set; }

    [XmlElement(ElementName = "UTILITYID")]
    public string UtilityId { get; set; }

    [XmlElement(ElementName = "LONTALKKEY")]
    public string LonTalkKey { get; set; }

    [XmlElement(ElementName = "DOWNLIMIT")]
    public string DownLimit { get; set; }
}

public class CreateParametersGeoGraphicCoordinates
{
    [XmlElement(ElementName = "LATITUDE")]
    public string Latitude { get; set; }

    [XmlElement(ElementName = "LONGITUDE")]
    public string Longitude { get; set; }
}

А для PayLoads у меня есть следующий родовой класс и DeviceManager.Create Payload, специфичный для класса:

Создать PayLoad

public class CreatePayLoad
{
    [XmlElement(ElementName = "DEVICEID")]
    public string DeviceId { get; set; }
}

* 1047 PAYLOAD *

[XmlRoot(ElementName = "RETURNS")]
public class PayLoad<T> where T : new()
{
    public PayLoad()
    {
        ApiPayLoad = new T();
    }

    /// <summary>
    /// Contains the payload from the command.
    /// </summary>
    [XmlElement(ElementName = "APIPAYLOAD")]
    public T ApiPayLoad { get; set; }

    /// <summary>
    /// Status of the call
    /// </summary>
    [XmlElement(ElementName = "STATUS")]
    public string Status { get; set; }
}

Так что в моем коде я могу сделать вызов следующим образом:

Пример использования

//Create the parameters
var parameters = new Create
                     {
                         Description = "Description",
                         GatewayId = "GatewayId",
                         Name = "NameOfDevice",
                         GeographicCoordinates = new CreateParametersGeoGraphicCoordinates
                                                     {
                                                         Latitude = "Lat",
                                                         Longitude = "Long"
                                                     },
                         Meter = new CreateMeter
                                     {
                                         TransformerId = "ID",
                                         DownLimit = "120"
                                     }
                     };

//Serialize the parameters to xml
string sXmlParameters = Helper.SerializeToXml<Create>(parameters);

//API call
string apiPayLoad = DeviceManager.Create(apiKey, sXmlParameters);

//Deserialize payload
var payLoad = Helper.DeserializeFromXml<PayLoad<CreatePayLoad>>(apiPayLoad);

Может кто-нибудь поделиться своими идеями и лучшими способами справиться с этим? Пожалуйста, имейте в виду, что в системе около 300 методов, некоторые с очень сложными параметрами XML, где некоторые свойства являются необязательными, некоторые обязательными, если используются свойства A, B или C и т. Д.

Я смотрел на XSD.exe, но сгенерированный код не очень понятен и не очень хорошо обрабатывает коллекции.

Друг также предложил шаблоны T4, где можно генерировать классы на основе шаблонов, но я не нашел там хороших примеров.

Я не уверен, хорошо ли я объяснил себя, если мне неясно - пожалуйста, дайте мне знать, и я постараюсь уточнить.

Спасибо, ШП-он

Ответы [ 2 ]

0 голосов
/ 17 марта 2012

Они не являются строго типизированными, все API принимают sXmlParameters и определяются только текстовой документацией. С помощью XSD.exe я создал примеры XML, затем сгенерировал xsd, и из этого я создал несколько файлов .cs. Однако это очень трудоемкая задача.

Мне порекомендовали изучить беглые интерфейсы DSL, которые могли бы помочь мне в создании sXmlParameters.

var result = DeviceManager.Create(apiKey,
  Parameters.
  .Type(Parameters.Create)
  .Name("Name of Device")
  .Description("Description of Device")
  .Coordinates("Lat","Long")
  .Validate()
  .asXML()
);

Используя это, я могу создавать параметры из кода и иметь базовый класс, проверяющий обязательные поля перед возвратом параметров в виде XML.

Однако сопоставление PayLoads для каждого результата все равно будет трудоемкой задачей. Я думал использовать шаблоны T4 для генерации классов на основе XML или similair.

0 голосов
/ 17 марта 2012

Глупое время вопроса: так вы говорите, что ни один из API не является строго типизированным?То есть все подписи:

public string Create(string sKey, string sXmlParameters) 

А схема входного параметра "sXmlParameters" определяется только текстовой документацией?Если это так, то я думаю, что вы переосмысливаете вещи, и написание методов анализа ответов будет столь же эффективным, как и создание классов и использование шаблонов и методов приведения для преобразования ответов в объекты.

Тем не менее, вы упоминаете XSD.exe, так что, может быть, есть определенные схемы для входов и выходов?Если это так, я бы создал эти определения классов с помощью инструмента XSD и не беспокоился о том, что они не «аккуратны» - вы никогда не смотрите на эти файлы C #, вы просто используете объекты.С точки зрения их слабости в отношении коллекций - если вы пытаетесь фильтровать / сортировать / проверять / просматривать сложные вложенные данные коллекции, я бы посоветовал вам взглянуть на выражения запросов LINQ;они позволят вам быстро захватить нужные вам предметы.Конечно, они мало помогают в создании объектов, но я не думаю, что есть быстрое решение для этого.

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