Welcome to CCF 2.0. То, о чем так долго говорили большевики... We exposed to see at least 3 great features - 1) . TAPI (and TSAPI) transfers call context to desktop application (called in CCF Agent Desktop), 2). External applications are hosted in .NET environment, 3) BizTalk BAF (Adapter Framework) briges RT application to messaging. Concerning BizTalk is much more to say from CCF perspective - BAM in action, consuming web-exposed orchestrations and so on. It's real field-test for BTS!
But before you start, you need to make up the framework installation. There is a document called 'Developer's Guide' that significally helps. Read it carefully. Here I'll highlight the principal points.
1. Start with DB installations - CSR and CSS folders (under Database).
2. Add yourself to both DB users as db_owner! Alternatively, you may follow Guide's recommeded way - add youlself to ccfusers group, but currently this group is not mapped correcly to SQL Logins. Better yet - add yourself to this group and to DBs separately!
2a). Insert new records to CCFUser table in ContactCenter DB. One for any account that intended to run Agent Desktop. For example
INSERT INTO CCFUser (UserID, DomainUser, FirstName, LastName, Type,Picture)
VALUES (6, N'framhostolegk', N'Oleg', N'Kleiman', 1, 'DemoAgentOne.jpg')
3. Copy DemoTAPI provider to system32. The Softphone application is distributed as part of AgentDesktop setup and not separately as Guide states.
4. Test Softphone till you fill comfortable with it and understand its functionality.
5. Install Web Services. Remove anonymous access to all of them! It's critical to Agent Desktop since it depends, for example, on ContactCenter.AgentStats.AgentLogin2() method to authenticate the agent and expect to find the appropriate record in ContactCenter DB (CCFUser table)
5a. Edit web.config for ContactCenter and ContactCenterAIF Web Services. Unless you've created and properly modied 'ccfusers' domain group, edit authorization section to allow access to all users.
6. Run Agent Desktop and Softphone simultaneously. You will see the first amazing feature - desktop application gets TAPI call context!
Next features - in next post!
Чтобы понять, как работает authentication, напишем простой Web service с одним методом :
[WebMethod]
public string GetUserIdentity()
{
try
{
IPrincipal principal = base.User;
string strUserName = principal.Identity.Name;
return strUserName;
}
catch
{
return null;
}
}
Для того, чтобы этот код исполнял именно то, для чего он предназначен - вернуть имя того, кто его запускает (это совсем не одно и то же, что currently logged user), понадобятся 2 дополнительные настройки –Directory Security option from IIS Admin и его web.config. Во-первых, IIS Admin. Если включить Enable Anonymous Access, то никакой authentication просто не будет производиться. В этом, собственно, и состоит смысл anonymous access. Т.е. для начала он должен быть убран. Теперь web.config. Its authentication section is just duplicates the IIS Admin options and hence confusing. Bear in mind that Web Services are configured thru web.config to bring the illusion of independency on IIS for multi-platform deployment. Whatever! Just make this section to look like
<authentication
[показать]
[показать]Задача такая : сканируем ftp location; для каждого обнаруженного там файла - обновляем базу, соответственно его содержанию. Например, файлы, кот. будут находиться на ftp, имеют такую структуру:
<
ns0:Result batchNum="22" xmlns:ns0="http://pbControl.ResultSchema" />всего с одним attributed element для простоты. В базе обновляем таблицу, в кот., скажем, одно из полей равняется атрибуту batchNum.
Можно, конечно, писать orchestration - receive shape для получения из ftp, transform shape (obviously embraced by construction block) with mapping и send shape, связанный с SQLAdapter-generated-schema, в кот. есть вызов stored procedure или updategram на обновление. Работает.
Но можно и не писать orchestration вовсе : создаем receive port (with ftp receive location), в его inbound maps добавляем наш map из transform shape, т.е. любой поступающий туда документ из ftp будет сразу преобразовываться в SQL updategram - 2 shape из orchestration уже не понадобятся. Можно, кстати, добавить несколько inbound maps - каждый для документов со своей schema. Можно добавить и несколько receive locations - send port ведь привязывается к receive port, не к receive location. Осталось добавить send port для SQL. Добавили. Теперь свяжем его напрямую с уже созданным receive port. Через filter : Edit->Filters & Maps->Filters. Фильтр будет такой : Property->BTS.ReceivePortName, Operation->'==', Value->[Имя созданного receive port].Вот и все. Orchestration не понадобился, а вместе с ним и its performance penalty.
Как же это работает? Чтобы понять, стоит просто взглянуть на BTSSubscriptionViewer - сконфигурированный так send port просто создает свой subscription
[показать]
[показать]
Детство, зрелость, старость легко прожить правильно и полно. Юность легко делается недостойна подлинного человека. Не потому ли пустые краснобаи так любят кричать о юности? Для них это самая приятная пора: приятно вспомнить, как мало от тебя требовалось и как много давалось.
Лагерквист. В мире гость.
Сцена 2158. Ночь. Те же и v_g_t.
v_g_t (Баском. Уверенно, как человек, чувствующий, что никто на него не насрал ).
Я нашел себе работу. И машину я купил.
И детишки подрастают. Да и сам я полон сил.
И уже уже на сайтах мелких я советы не даю.
В модераторы подался - модерирую струю.
Я подкован, я начитан, я умен, я деловит
и стишками пробавляюсь иногда, чтоб сделать вид.
Не пускаю пыль в глаза я, никуда не залезаю,
eсли что я знаю твердо, так скажу об этом гордо.
Но родительский фантом
оставляет мне кондом.
Массы (задумчиво, как водится в массах, без запятых). Ну а сзади а сзади? Mожет не еврей?
v_g_t (Устало. Пока он говорит, фоном нарастает "Гимн пролетарию" Галича)
Никакого барабана. Гегемон я или нет?
Почему я должен слушать долженэтот ваш флюдийский бред?
Я в семью пришел с работы. У меня шиши-шабат.
Эти мне сюр-реалисты, в голове от них набат!
Я возьму с Пашуней литру, а не хватит - так и два.
А когда проснусь - чтоб тихо. "Не болеет голова".
Маргарита (немного "акая"). Не правда ли, весна скоро?
ladyl. Какой чудесный вопрос, душенька! Сама-то я не очень знаю, но вот END обязательно скажет.
END'у (дательный падеж - кому, чему)
Конец? пи...дец? фиаско?
Умом хоть не обласкан,
но форум для меня -
как сено для коня.
Маргарита (Обращаясь к Евгения. Нежно).Ой, какой у вас разрезик сегодня! Неужели сами выбирали?
Евгения(Гневно).
Массы (Некультурные). Так телись!
[показать]Главный батька
Lab 1. PermitOnly()
Scenario : despite the external assembly has been granted the permissions (by policy config file) to call SqlConnection.Open(),such the attempt is failed because calling assembly want to restrict the caller notwithstanding policy.
1.1.1). Preparing policy config file : Create CodeGroup with URLMembershipCondition that points to the folder with assemlby to be loaded
1.1.2) Create PermissionSet includeing 2 permissions - SecurityPermission with Assertion and Execution flags and unrestricted SqlClientPermission .This will grant the assembly to be loaded the SQLConnection.Open() permissions
1.2) Load and invloke the external assembly
1.2.1). External assembly is loaded (LoadFrom) by codebase. Its evidence established and captured
Assembly assm = Assembly.LoadFrom(codebase);
Evidence evidence = assm.Evidence;
1.2.2). Policy loaded from .config file at AppDomain level. The evidence of the loaded assembly is resolved thru the policy returning "effective permission set" for this AppDomain for loaded assembly.
PolicyLevel polLevel = SecurityManager.LoadPolicyLevelFromFile(@"folknote.config", PolicyLevelType.AppDomain);
PolicyStatement statement = polLevel.Resolve(evidence);
PermissionSet ps = statement.PermissionSet;
1.3) Construct the required permission set (for Execution only)
IPermission perm = new SecurityPermission(SecurityPermissionFlag.Execution);
PermissionSet requiredPS = new PermissionSet(PermissionState.None);
requiredPS.AddPermission(perm);
1.3.1) Check if loaded asembly has been granted required Execution permissionsbool bRes = requiredPS.IsSubsetOf(ps);
1.4) Enable further running only under permitted permissions!requiredPS.PermitOnly();
1.5.1) Compile and run. Check the security exception is raised.
1.5.2) Remove the PermitOnly() call from caller. Run once again - no security exception is raised this time.
Note: security check is lazy as possible. You was eble to create new SqlConnection object but actual invocation is only checked when you call SqlConnection.Open() method.
Lab 2. Assert()
В прошлом lab'е создалась довольно абсурдная ситуация : несмотря на то, что loaded assembly has been explicitly (by policy config) granted SqlClientPermission, it was failed to actually invoke Open() method! Почему это абсурд? Потому, что с одной стороны, host, кот. хочет to tune permissions, seems to be able to ignore policy settings. From other hand, it's the primary goal of the policy files - to tune security declaratively! Such kind of absurd решается с помощью Assert().Вызывая Assert(), client states that it willing to restrict the stack walk upstream, till existing [bp]. Философски выражаясь, это можно сформулировать примерно так: я уважаю ограничения, высталенные by callers, но я все-таки хочу вызвать то, что мне надо; пусть же нас рассудит policy. А policy рассуждает так: с одной стороны, у callee есть permissions на вызов - надо бы разрешить, с другой стороны - сам caller поставил PermitOnly(), значит у него были какие-то причины? Поэтому поищем среди permissions callee - SecurityPermissions.Assert (see lab1): если стоит - разрешить Assert() и сам вызов, разумеется; если нет - администратор, видимо, лучше знает.
2.1) Insert Assert invocation into callee code:
SqlClientPermission perm = new SqlClientPermission(PermissionState.Unrestricted);
perm.Assert();
2.2) Compile, run and see success invlocation of SqlConnection.Open()
2.3) Remove Assertion from Permission section of desired PermissionSet. Run and see SecurityException raised.
Вывод: всегда включайте в код своих assemblies Assert() - пусть администратор policy сам разбирается.
Lab 3.Demand()
Lab 4.Deny()