Всех приветствую!

Делаю веб-сервис. Методы Post и Get работаю без проблем. А вот с Put и Delete проблема.

Сразу была ошибка:

Изображение удалено. ее победил изменив web.config как описано в статье. Но после этого появилась новая:

Изображение удалено.

Подскажите что делать?

На всякий случай веб-сервис:

[OperationContract]
        [WebInvoke(Method = "DELETE", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json, UriTemplate = "/contact")]
        public void Delete(string deleteData)
        {
            var delete = new Delete(UserConnection)
                .From("Contact")
                .Where("Id").IsEqual(Column.Parameter(deleteData));
            delete.Execute();
        }
 
        [OperationContract]
        [WebInvoke(Method = "PUT", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json, UriTemplate = "/contact")]
        public void Put(string data)
        {
            var update = new Update(UserConnection, "Contact")
                .Set("Name", Column.Parameter("Bla-bla-bla"))
                .Where("Id").IsEqual(Column.Parameter(data));
            update.Execute();
        }

 

Нравится

3 комментария

Добрый день!

Попробуйте использовать эти методы, будут ли они у вас работать?

[OperationContract]
		[WebInvoke(Method = "PUT", UriTemplate = "TestPut/{testId}", RequestFormat = WebMessageFormat.Json,
			ResponseFormat = WebMessageFormat.Json)]
		public string TestPut(string testId) {
			return UserConnection.CurrentUser.Name +  " TestPUT";
		}
 
		[OperationContract]
		[WebInvoke(Method = "DELETE", UriTemplate = "TestDelete/{testId}", RequestFormat = WebMessageFormat.Json,
			ResponseFormat = WebMessageFormat.Json)]
		public string TestDelete(string testId) {
			return UserConnection.CurrentUser.Name + " TestDELETE";
		}
	}
}

 

Дима Вовченко,

Спасибо за ответ!

К сожалению не помогло.

Pavel Litvinovich,

Хм, вы же обращались к запросам так "TestPut/someId" ?

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

Показать все комментарии

Собираюсь использовать службу DataService с клиентской части, так как совсем не разбираюсь в С#. Но в документации для чтения и добавления примеры для JS есть, а для удаления и обновления записей -
нет. Прошу помощи: буду очень признателен за пример удаления и обновления записи через DataService на из клиентской части)

Нравится

2 комментария

Для обновления ищите по конфигурации слова "Terrasoft.UpdateQuery"
примеров множество, вот из OpportunityManagementEndOfStagePreconfiguredPage:

var updateQuery = Ext.create("Terrasoft.UpdateQuery", {
	rootSchemaName: "Activity"
});
updateQuery.filters.addItem(this.Terrasoft.createColumnFilterWithParameter(
		Terrasoft.ComparisonType.EQUAL, "Id", activityId));
updateQuery.setParameterValue("Status",
		ConfigurationConstants.Activity.Status.Cancel,
		this.Terrasoft.DataValueType.LOOKUP);
updateQuery.execute(function() {
	this.loadActivities();
}, this);

Удаление по словам "Terrasoft.DeleteQuery", примеров так же очень много, вот из DocumentRelationshipDetailV2:

var deleteQuery = this.Ext.create("Terrasoft.DeleteQuery", {
	rootSchemaName: "DocumentRelationship"
});
var masterRecordId = this.get("MasterRecordId");
var filters = this.getDeleteRelationFilters(masterRecordId, selectedRows);
deleteQuery.filters.add("DocumentsFilter", filters);
deleteQuery.execute(function() {
	this.hideBodyMask();
	this.deselectRows();
	this.reloadGridData();
}, this);

"Максим Шевченко" написал:

Для обновления ищите по конфигурации слова "Terrasoft.UpdateQuery"

примеров множество, вот из OpportunityManagementEndOfStagePreconfiguredPage:

var updateQuery = Ext.create("Terrasoft.UpdateQuery", {

        rootSchemaName: "Activity"

});

updateQuery.filters.addItem(this.Terrasoft.createColumnFilterWithParameter(

                Terrasoft.ComparisonType.EQUAL, "Id", activityId));

updateQuery.setParameterValue("Status",

                ConfigurationConstants.Activity.Status.Cancel,

                this.Terrasoft.DataValueType.LOOKUP);

updateQuery.execute(function() {

        this.loadActivities();

}, this);

Удаление по словам "Terrasoft.DeleteQuery", примеров так же очень много, вот из DocumentRelationshipDetailV2:

var deleteQuery = this.Ext.create("Terrasoft.DeleteQuery", {

        rootSchemaName: "DocumentRelationship"

});

var masterRecordId = this.get("MasterRecordId");

var filters = this.getDeleteRelationFilters(masterRecordId, selectedRows);

deleteQuery.filters.add("DocumentsFilter", filters);

deleteQuery.execute(function() {

        this.hideBodyMask();

        this.deselectRows();

        this.reloadGridData();

}, this);


Большое спасибо!

Показать все комментарии

Здравствуйте, изучил тему по ссылке. В частности последний пост.
Возник ряд вопросов:
- Как правильно использовать dbExecutor для избежания утечки памяти?
- В каких именно случаях нужно пользоваться указанным в теме подходом?
- Всегда ли нужно оборачивать методы Execute() и ExecuteScalar() классов Select, Insert, Update в using, если нет, то в каких случаях это не обязательно?

Используемые версии приложения - от 7.4 и выше

Нравится

5 комментариев

продублирую пост из ссылки в данную тему:

"Венжик Игорь" написал:Часто возникает ситуация когда необходимо сделать специфичечкий запрос к БД, который невозможно или сложно воспроизвести с помощью бизнес-сущностей. Например запросы к таблицам прав доступа, к системным таблицам. (Не законченная статья...)

В таких случая необходимо строить кастомные запросы:

Select select =
        new Select(UserConnection)
                .Column("Id")
                .Column("SysSchemaId")
                .Column("Name")
                .Column("SysSchemaManagerName")
                .Column("SysSchemaFolderId")
                .Column("MetaDataModifiedOn")
        .From("VwSysSchemaInSolution")
        .Where("SysSolutionId").IsEqual(new QueryParameter("solutionId", userConnection.Solution.Id))
                .And("SysSchemaId").In(schemas)
                .And("SysSchemaStateInSolution").IsNotEqual(Column.Const((int)StoringObjectState.Deleted))
                .And().OpenBlock("LockedById").IsNull()
                        .Or("LockedById").IsEqual(new QueryParameter("currentUserId", userConnection.CurrentUser.Id))
                .CloseBlock()
                as Select;
Для выполнения запросов к БД в нашей системе есть специальный объект DBExecutor. Экземпляр которого содержится в каждом UserConnection-е. То есть одному пользователю всегда доступен только один экземпляр DBExecutor-а, и пользователь не может сам создавать новые экземпляры.
Что бы получить экземпляр DBExecutor-а необходимо вызвать метод UserConnection.EnsureDBConnection().
using (var dbExecutor = UserConnection.EnsureDBConnection()) {

}
Для вызова всегда необходимо использовать конструкцию using!

Давайте раcсмотрим несколько вариантов работы

Допустим нам необходимо выполнить простой запрос:

Select select =
        new Select(UserConnection)
                .Column("Name")
        .From("Contact")
        .Where("City").IsEqual(Column.Parameter("Киев"))

Получение значения из первой строки, первого столбца выборки

Есть два способа

var name = select.ExecuteScalar();
или
string name;
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
        name = select.ExecuteScalar(dbExecutor);
}
Оба способа вернут один и тот же результат. Если вы выполняете одиночный запрос тогда используйте первый вариант, он является оберткой над вторым. Второй вариант, с передачей dbExecutor-а, будет полезен если выполнять несколько запросов к БД в рамках одной транзакции.

Получение списка значений:

List names = new List();
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
        using (var reader = select.ExecuteReader(dbExecutor)) {
                while(reader.Read()) {
                        int columnOrdinal = reader.GetOrdinal("Name");
                        names.Add(reader.GetString(columnOrdinal));
                }
        }
}

Выполнение запроса в рамках транзакции:

Оба запроса в базу будут выполнены в рамках транзакции и в случае свала транзакция откатится.

List names = new List();
using (var dbExecutor = UserConnection.EnsureDBConnection()) {

>>      dbExecutor.StartTransaction();
       
        using (var reader = select.ExecuteReader(dbExecutor)) {
                while(reader.Read()) {
                        int columnOrdinal = reader.GetOrdinal("Name");
                        names.Add(reader.GetString(columnOrdinal));
                }
        }
        insert.Execute(dbExecutor);

>>      dbExecutor.CommitTransaction();

}
Транзакция начинается вызовом метода dbExecutor.StartTransaction и заканчивается вызовом CommitTransaction или RollbackTransaction. В случае когда выполнение вышло за область видимости блока using и CommitTransaction не был вызван, происходит автоматический откат транзакции. Таким образом нет необходимости оборачивать транзакцию в try/catch блок, т.к. если был свал во время выполнения транзакция автоматически откатится.

Внимание! В текущей реализации даже если не передавать dbExecutor в метод Execute(), все равно запрос будет выполнен в текущей транзакции, если такая существует. Но для избежания сложностей в будущем, всегда при выполнении нескольких запросов в рамках транзакций - всегда передавайте dbExecutor в методы Execute, ExecuteReader, ExecuteScalar.

Здравствуйте!

Методы Execute() и ExecuteScalar() классов Select, Insert, Update в using оборачивать не нужно.
Для Select-ов ExecuteScalar или Execute, который принимает анонимный метод - также не стоит оборачивать в using.
Для Select-а, который использует конструкцию List names необходимо использовать Using:

List names = new List();
using (var dbExecutor = UserConnection.EnsureDBConnection()) {
using (var reader = select.ExecuteReader(dbExecutor)) {
while(reader.Read()) {
int columnOrdinal = reader.GetOrdinal("Name");
names.Add(reader.GetString(columnOrdinal));
}
}
}

Добрый день! Давно и сильно интересует вопрос, каким образом обернуть в транзакцию событийный процесс объекта при сохранении/удалении? Для гарантированной согласованности данных в разных сущностях, когда изменения в одном объекте влекут изменения в другом связанном.

Показать все комментарии

Добрый день! Решил освоить интеграцию с bpmonline 7.4 через oData. Взял пример который был на вебинаре по разработке на 7.4 и он не работает.

А конкретнее не работают методы PUT и DELETE. То есть я могу удачно авторизироваться и создать запись. Но вот при попытке удалить или изменить получаю ошибку 405 (Недопустимый метод). Я так полагаю проблема где-то в настройках iis или config файле сайта. Подскажите пожалуйста что нужно настроить.

Нравится

11 комментариев

Здравствуйте, Вячеслав!
Приведите, пожалуйста, пример кода, который не работает.
Необходимые компоненты сервера можно посмотреть в руководстве по установке, например тут:
http://www.training.terrasoft.ru/sites/default/files/BPMonline_Setup_Gu…

Код полностью взят из примера, который демонстрировался в вебинаре по 7,4.

static void UpdateRecord(string guid)
{
 // Создание экземпляра запроса для изменения контакта с заданным идентификатором.
 var request = HttpWebRequest.Create(serverUri + "ContactCollection(guid'" + guid + "')") as HttpWebRequest;
 request.CookieContainer = bpmCookieContainer;
 // Для изменения записи используется метод PUT.
 request.Method = "PUT";
 request.Accept = "application/atom+xml";
 request.ContentType = "application/atom+xml;type=entry";
 
 // Создание сообщения xml, содержащего данные об изменяемом объекте.
 var content = new XElement(dsmd + "properties", new XElement(ds + "Name", "New"));
 var entry = new XElement(atom + "entry", new XElement(atom + "content", new XAttribute("type", "application/xml"), content));
 
 // Запись сообщения xml в поток запроса.
 using (var writer = XmlWriter.Create(request.GetRequestStream()))
   {
       entry.WriteTo(writer);                
   }
 // Получение ответа от сервиса о результате выполнения операции.
 using (WebResponse response = request.GetResponse())
   {
        Console.WriteLine("Данные контакта с идентификатором " + guid + " успешно обновлены.");
    }
}

Метода PUT не существет. Надо использовать либо GET либо POST

Попробуйте подкорректировать конфигурационный файл (предварительно сохраните копию):
..\Terrasoft.WebApp\Web.config

Необходимо добавить 2 строчки в соответствующие блоки (system.webServer самый нижний):

<remove name="WebDAVModule" />
<remove name="WebDAV" />
  <system.webServer>
    <httpErrors errorMode="Detailed" />
    <validation validateIntegratedModeConfiguration="false" />
    <modules>
      <remove name="WebDAVModule" />
      <!--...-->
    </modules>
    <handlers>
      <remove name="WebDAV" />
      <!--...-->
    </handlers>
    <!--...-->
  </system.webServer>

"Толмачев Дмитрий Юрьевич" написал:

Необходимо добавить 2 строчки в соответствующие блоки (system.webServer самый нижний):

<remove name="WebDAVModule" />

<remove name="WebDAV" />

Огромное спасибо! Сразу заработало!

"Олейников Владимир Владимирович" написал:

Метода PUT не существет. Надо использовать либо GET либо POST

http://academy.terrasoft.ru/documents/?product=SDK&ver=7.4.1
https://ru.wikipedia.org/wiki/HTTP#.D0.9C.D0.B5.D1.82.D0.BE.D0.B4.D1.8B

Есть ещё вопрос:

Как очистить справочное поле через метод PUT ?
Пробовал передавать Guid.Empty.ToString() выдает ошибку 500. null и пустая строка вызывают ошибку 400.

Поставить новый id - без проблем. А вот очистить не получается.

А через Convert.ToString() ?

Попробуйте так:

    XElement brandElement = new XElement(ds + "SmrBrandId");
    brandElement.SetAttributeValue(dsmd + "null", true);
    var content = new XElement(dsmd + "properties",
            brandElement
    );

Но работает не со всеми полями. По моему зависит от обязательности заполнения и установки значений по умолчанию.

И снова я безмерно благодарен! Всё получилось. Справочное поле стало пустым.

Но появилась другая проблема.
Дело в том, что я пишу интеграцию с сервисом работающем на framework 2.0
Я взял всё тот-же проект из примера выставил в нем framework 2.0
xml сообщение я формирую через XmlDocument тут всё хорошо. Но в этом месте:

using (WebResponse response = request.GetResponse())

Скрипт как-бы зависает. То есть после него совсем ничего не происходит. Никаких ошибок, но и дальше скрипт не выполняется. Просто мертвая точка. И данные в bpm не заносятся.
При чем работает только с framework 4.0. Даже с framework 3.5 не работает.

Если, ничего не меняя в коде, выставить framework 4.0 то всё проходит успешно.

Подскажите, пожалуйста чего не хватает?

Здравствуйте, Вячеслав!
Судя по описанию тут та же проблема:
http://stackoverflow.com/questions/11319891/httpwebrequest-only-running…

Попробуйте посмотреть Fiddler'ом, есть ли разница в запросах.

Fiddler показал что запрос не отправляется в принципе. На авторизацию запрос проходит и удачно, а вот на изменение нет.

Погуглив более тщательно проблема была обнаружена. Дело всё в том что перед выполнение запроса нужно закрывать поток RequestStream. И вот framework 4.0 делает это самостоятельно перед выполнением функции GetResponse, а все фреймворки ниже не умеют этого. Поэтому перед

using (WebResponse response = request.GetResponse())
{
   /*---------*/
}

надо писать: request.GetRequestStream().Close()

И запрос должен выглядеть так:

request.GetRequestStream().Close();
using (WebResponse response = request.GetResponse())
{
   /*---------*/
}

И вот так всё работает.

Показать все комментарии