Необходимо интегрировать сущность обращения.
Пишу веб-сервис. В нем необходимо реализовать логику. Что он должен в себя принимать? Свойства (номер, uid, комментарий, и пр.) либо объект класса TSRequest, например, чтобы сервис был расширяемым? Есть примеры интеграции, которая хорошо работает у вас?
Нравится
А уже готовые интеграционные сервисы тебе не устроят, которые работают внутри bpmonline? Подробности тут
А уже готовые интеграционные сервисы тебе не устроят, которые работают внутри bpmonline? Подробности тут
Если я использую готовые сервисы, то где писать логику обработки входящих данных? Получается внешняя система дергает какие угодно методы, которые правят данные, как ей угодно. К примеру существует контакт с UID1, а система источник попытается ВСТАВИТЬ контакт с UID1, и в этом случае, должен сработать UPDATE (и наоборот). Или же, приходит по интеграции обращение, оно ссылается на контакт, которого нет в системе, его необходимо затянуть из внешней системы, а затем сохранить обращение. Что делать в таком случае?
Гречушкин Александр Юрьевич,
Вы пишите свой сервисный класс, пишите необходимые вам методы, вставки, обновления и т.д., в этом классе принимаете например входящую JSON, эту строку десериализуете, а с полученным объектом уже работаете
public class Contactor { [DataMember] public string id { get; set; } public string Type { get; set; } public string Code { get; set; } public string Name { get; set; } public string NameFull { get; set; } public string EDRPOU { get; set; } public string INN { get; set; } public string JurFiz { get; set; } public List<ContactInfo> ContactInfo { get; set; } public List<Contact> Contacts { get; set; } public List<TT> TT { get; set; } } [DataContract] public class RootObject { [DataMember] public List<Contactor> Contactors { get; set; } } [OperationContract] [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] public void AddDataInDB(string input) { RootObject rootObject = JsonConvert.DeserializeObject<RootObject>(input); foreach (var account in rootObject.Contactors) { AddAccount(account); } } private void AddAccount(Contactor account) { var entity = GetEntity("Account", "id", account.id); entity.SetColumnValue("Name", account.Name); entity.SetColumnValue("TypeId", GetLookupValueByName("AccountType", "Name", account.Type)); entity.SetColumnValue("Code", account.Code); entity.Save(); // AddAccountCommunication(account.ContactInfo, account.Id); // AddAccountContacts(account.Contacts); }
Литвинко Павел,
а в случае с обновлением и удалением? Как в JSONе понять тип операции?
Литвинко Павел,
есть ли пример запроса из внешней системы на добавление или обновление сущности в bpm?
Гречушкин Александр Юрьевич пишет:
В случае обновления, вы просто сначала проверяете в БД, есть такая запись или нету, если есть, то обновляете ее, если нету, то создаете, одним методом можно решить вопрос.
Что касается удаления, то в JSON, из внешней системы, добавьте атрибут, например Delete = true/false, а в БПМ, проверяете, если true - то пишите запрос на удаление, если false, то идете создавать/обновлять запись
Гречушкин Александр Юрьевич пишет:
Литвинко Павел,
есть ли пример запроса из внешней системы на добавление или обновление сущности в bpm?
Тут, смотря из какой внешней системы, но суть везде одна, внешняя система должна сначала авторизоваться в BPM "http://[АДРЕСС_BPM]/ServiceModel/AuthService.svc/Login";
После авторизации, создается еще один запрос с полученными куками и токеном, где вызывается уже написанный нами метод, в который передается JSON/XML и т.д. строка с данными
Литвинко Павел пишет:
Гречушкин Александр Юрьевич пишет:
В случае обновления, вы просто сначала проверяете в БД, есть такая запись или нету, если есть, то обновляете ее, если нету, то создаете, одним методом можно решить вопрос.
Что касается удаления, то в JSON, из внешней системы, добавьте атрибут, например Delete = true/false, а в БПМ, проверяете, если true - то пишите запрос на удаление, если false, то идете создавать/обновлять запись
Так же это можно решить со стороны внешней системы, например, у себя написать 3 метода, Добавление, Обновление и Удаление, а внешний сервис уже будет вызывать нужный метод, в зависимости от того, что нужно сделать с теми или иными данными
Литвинко Павел,
Конкретно для примера с Contractor можно вызов сервиса, пожалуйста?
Гречушкин Александр Юрьевич,
http://Адрес:Порт/0/rest/UsrInputAccount/AddDataInDB
Пример
[ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] public class UsrInputAccount { //структура json [OperationContract] [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] public void AddDataInDB(string input) {} }
А для того, чтобы ваш сервис стал доступен из вне, вы должны проделать следующее:
В папке сайта в котором написан наш сервис, *сайт*\Terrasoft.WebApp\ServiceModel Создаем файл «UsrLaunchProccService.svc» //Создавайте название идентичное названию вашего класса В содержимое файла пишем: <%@ ServiceHost Language="C#" Debug="true" Service="Terrasoft.Configuration.UsrLaunchProccService" CodeBehind="UsrLaunchProccService.svc.cs" %> 3. В папке *сайт* \Terrasoft.WebApp в файле Web.config рядом с другими локациями, добавляем: <location path="ServiceModel/UsrLaunchProccService.svc"> <system.web> <authorization> <allow users="*" /> </authorization> </system.web> </location> 4. В папке *сайт*\Terrasoft.WebApp\ в файле Web.config в секции appSettings меняем значение ключа AllowedLocations. В значение добавляем: ServiceModel/UsrLaunchProccService.svc; 5. В папке *сайт*\Terrasoft.WebApp\ServiceModel\http в файле services.config в блоке сервисов добавляем: <service name="Terrasoft.Configuration.UsrLaunchProccService"> <endpoint name="UsrLaunchProccServiceEndPoint" address="" binding="webHttpBinding" behaviorConfiguration="RestServiceBehavior" bindingNamespace="http://Terrasoft.WebApp.ServiceModel" contract="Terrasoft.Configuration.UsrLaunchProccService" /> </service> 6. В папке *сайт*\Terrasoft.WebApp\ServiceModel\https в файле services.config в блоке сервисов делаем то же самое, что и в пункте 5. Все, сервис будет доступен по адресу: http(или https)://адрес-сайта/0/ServiceModel/UsrLaunchProccService.svc
Литвинко Павел,
А GetEntity и SetColumnValue это самописные методы или что-то нужно подключить, чтобы они работали?
Гречушкин Александр Юрьевич пишет:
А GetEntity и SetColumnValue это самописные методы или что-то нужно подключить, чтобы они работали?
GetEntity расширенный, использую для проверки существования записи, если нету, то создаю, SetColumnValue от террасофта, используется чтобы установить значение в колонку, нужна библиотека: using Terrasoft.Core.Entities;, так же можете сразу добавить следующие, а там уже если чего не будет хватать, то добавите
using System.Net; using Terrasoft.Common; using Terrasoft.Core; using Terrasoft.Core.DB; using Terrasoft.Core.Entities; using Terrasoft.Core.Store; using System; using System.Collections.Generic; using Newtonsoft.Json; using System.Runtime.Serialization; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Activation; using System.ServiceModel.Web;
Литвинко Павел,
т.е. не надо писать проверку на существование? А где можно его реализацию взять? И куда положить, в какой пакет?
Гречушкин Александр Юрьевич,
Проверку писать надо, в этом примере, я использую свой метод, он является расширением базового функционала метода GetEntity
Гречушкин Александр Юрьевич,
Вот, мой GetEntity, проверяет существует или нет, если нет, то создает.
public Entity GetEntity(string schemaName, string filterColumnName, string filterValue) { var esq = new EntitySchemaQuery(userConn.EntitySchemaManager, schemaName); esq.AddAllSchemaColumns(); esq.Filters.Add(esq.CreateFilterWithParameters( FilterComparisonType.Equal, filterColumnName, filterValue)); var entityCollection = esq.GetEntityCollection(userConn); if (entityCollection.Count == 0) { var entity = userConn.EntitySchemaManager.GetInstanceByName(schemaName).CreateEntity(userConn); entity.SetDefColumnValues(); var filterColumn = entity.Schema.Columns.GetByName(filterColumnName); entity.SetColumnValue(filterColumn, filterValue); entityCollection.Add(entity); } return entityCollection[0]; }
Литвинко Павел,
Нигде не могу найти
GetLookupValueByName. Это ваш метод? можете поделиться реализацией? или что нужно подключить для его использования?
Гречушкин Александр Юрьевич пишет:
GetLookupValueByName
Да, метод мой, поделиться могу, но зачем он вам, не понятно)
public string GetLookupValueByName(string schemaName, string filterColumn, string filterValue) { var entity = GetEntity(schemaName, filterColumn, filterValue); return entity.GetTypedOldColumnValue<string>(filterColumn); }
Литвинко Павел,
Как архитектурно правильно хранить вспомогательные методы? Отдельный файл исходного кода, который потом подключается к другим? Или замещать какой-то существующий? У меня облако и найти реализацию того или иного класса затруднительно..
Гречушкин Александр Юрьевич,
Отдельный исходный код, конечно, создаете его, затем на примере импорта наследуетесь от нового исходного кода так:
UsrMyIntegration : UsrExtendedMethods
Таким образом, вы сможете вызывать ваши кастомные методы из другого паблик класса. И опять ж таки на примере, примеров кода выше, вы сможете вызывать GetLookupValueByName, GetEntity и т.д., тем самым в одном исходном коде вы получите только вызовы методов, а сами методы будут отдельно и не будут захламлять в данном случае код интеграции.
Оптимально будет делать так:
1) Сервисный класс (в нем вызывается отдельно каждый метод интеграции, Контакты - один исходный код, Контрагенты - второй и т.д., заполняете здесь только вызовы.
using System.ServiceModel; using System.ServiceModel.Web; using System.ServiceModel.Activation; using System.Web; using Terrasoft.Core; using Terrasoft.Core.DB; using Terrasoft.Core.Entities; using System; using System.Collections.Generic; using System.Runtime.Serialization; using Terrasoft.Common.Json; using System.Net; using Newtonsoft.Json; namespace Terrasoft.Configuration { [ServiceContract] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)] class IntegrationService { UserConnection userConnection = (UserConnection)HttpContext.Current.Session["UserConnection"]; [OperationContract] [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)] public void StartProcessForUpdatedContract(RootObject data) { OpIntegration.CheckDataResponse(data, userConnection); } } }
2) Сами классы, которые вызываете, из примера выше создается StartProcessForUpdatedContract, в нем описывается структура json, xml и методы которые кладут их в БД.
3) Отдельный файл, в котором храните все кастомные методы, чтобы вызывать и получать их результат в классах пункта 2.
Литвинко Павел,
Получается сервис интеграции будет пронаследован от множества сущностей? Контрагенты, контакты и пр. Стоит ли их объединять в один класс, чтобы RootObject в нем имел много DataMember`ов и методов для манипуляции ими?
Литвинко Павел,
rootobject в вашем предыдущем примере кто передаст в
StartProcessForUpdatedContract?
rootobject со своим набором полей есть в каждом вызываемом методе, напиши мне в ЛС ваш скайп, покажу детальнее