|  24.11.2008, 11:07 | #1 | 
| Чайный пьяница | Создание и регистрация плагина на Execute и Retreive 
			
			Задача, которая была поставлена - необходимо было в целочисленные поля new_hour и new_min сущности new_task - возвращать часы и минуты в работе с задачей соответственно. Механику вычисления - пропущу, потому как она для каждого отдельного случая может быть уникальна. 1. Особенности регистрации - плагин на Execute (в моём случае я отслеживал получение данных в гриды MS CRM) необходимо регистрировать на Post Event не выбирая сущность и поля. Плагин на Retreive - необходимо регистрировать на Post Event, указывая имя сущности. 2. Особенности реализации: Execute: Код: public override void Execute(IPluginExecutionContext context)
{
       //метод для получения строки подключения к базе MS CRM будет приведён ниже
        string sqlConnectionString = GetSqlConnectionString(context.OrganizationName);
	//контролируем, что было событие Execute и Возвоащается FetchXml
	if (context.MessageName == "Execute" && context.InputParameters.Contains("FetchXml"))
	{
		XmlDocument indoc = new XmlDocument();
		indoc.LoadXml((string)context.InputParameters["FetchXml"]);
		//контролируем имя сущности поиск по которой был выполнен
		entityName = indoc.SelectSingleNode("//fetch/entity").Attributes["name"].InnerText;
				
		if (entityName != "new_task")
			return;
				
		//получаем Xml, который возвращается на сторону клиента
		XmlDocument outdoc = new XmlDocument();
				outdoc.LoadXml((string)context.OutputParameters["FetchXmlResult"]);
		foreach (XmlNode node in outdoc.SelectNodes("//resultset/result"))
		{
			Guid recordId = new Guid(node.SelectSingleNode("./new_taskid").InnerText);
			//чтобы не путать читателя кода поясню - GetWorkingMinutesCount - метод, который зачитывает данные из MS SQL сервера
			//в данном случае - время выполнения задачи в минутах
			calcMinCount = GetWorkingMinutesCount(recordId, sqlConnectionString);					
				
			XmlNode hoursnode = node.SelectSingleNode("./new_hour");
			if (hoursnode != null)
			{
				hoursnode.Attributes["formattedvalue"].Value =
				hoursnode.InnerText = ((int)(calcMinCount / 60)).ToString();
			}
			XmlNode minsnode = node.SelectSingleNode("./new_mins");
			if (minsnode != null)
			{
				minsnode.Attributes["formattedvalue"].Value =
				minsnode.InnerText = ((int)(calcMinCount % 60)).ToString();
			}
		}
		//возвращаем на клиента уже отформатированный Xml
		context.OutputParameters["FetchXmlResult"] = outdoc.OuterXml;
	}
}Код: public override void Execute(IPluginExecutionContext context)
{
	if (context.MessageName == "Retrieve")
	{
		entityName = context.PrimaryEntityName;
		//контролирую имя сущности, получение которой ведётся при помощи Retreive - например при открытии карточки
		if (entityName != "new_task")
			return;
		DynamicEntity currentEntity = (Microsoft.Crm.Sdk.DynamicEntity)context.OutputParameters.Properties["BusinessEntity"];
		if (!currentEntity.Properties.Contains("new_hour") && !currentEntity.Properties.Contains("new_mins"))
			return;
		Guid recordId = ((Microsoft.Crm.Sdk.Key)currentEntity.Properties["new_taskid"]).Value;
		string sqlConnectionString = GetSqlConnectionString(context.OrganizationName);
		int calcMinCount = GetWorkingMinutesCount(recordId, sqlConnectionString);
		if (currentEntity.Properties.Contains("new_hour"))
			((CrmNumber)currentEntity.Properties["new_hour"]).Value = calcMinCount / 60;
		if (currentEntity.Properties.Contains("new_mins"))
			((CrmNumber)currentEntity.Properties["new_mins"]).Value = calcMinCount % 60;
	}
}Код: 		protected string GetSqlConnectionString(string orgname)
		{
			RegistryKey key = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\MSCRM");
			//Retreive MSCRM DataBase connection string
			string configDBConnectionString = key.GetValue("configdb").ToString();
			//next part - i connect to config db and retreive data to config connection to client db
			DataSet clientDBConnectionData = new DataSet();
			using (SqlConnection connection = new SqlConnection(configDBConnectionString))
			{
				connection.Open();
				using (SqlCommand cmd = new SqlCommand())
				{
					cmd.Connection = connection;
					cmd.CommandType = CommandType.Text;
					cmd.CommandText = string.Format("Select SqlServerName, DatabaseName From Organization Where UniqueName = '{0}'", orgname);
					using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
						adapter.Fill(clientDBConnectionData);
				}
				connection.Close();
			}
			if (clientDBConnectionData.Tables.Count == 0 || clientDBConnectionData.Tables[0].Rows.Count == 0)
				throw new Exception("Check your config parameters!");
			string connectionString = string.Format("Data Source={0};Initial Catalog={1};Integrated Security=SSPI",
					new object[] { (string)clientDBConnectionData.Tables[0].Rows[0]["SqlServerName"], 
											   (string)clientDBConnectionData.Tables[0].Rows[0]["DatabaseName"]});
			return connectionString;
		}Последний раз редактировалось a33ik; 24.11.2008 в 11:20. | 
|  | 
|  24.11.2008, 12:36 | #2 | 
| Moderator | 
			
			Читать строку коннекции SQL из реестра, а так же делать прямые запросы - жесткий ансапорт! Перебирать XML... зачем такие сложности!!?? Используйте готовые сервисы!
		 
				__________________ http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.   MS Certified Dirty Magic Professional | 
|  | 
|  24.11.2008, 15:09 | #3 | 
| Чайный пьяница | Цитата: PS - для себя. О каких готовых сервисах идёт речь? Список ансапортеда - http://msdn.microsoft.com/en-us/library/bb928224.aspx и запросов к базе там ну нет. Структуру базы я не меняю. Последний раз редактировалось a33ik; 24.11.2008 в 15:18. | 
|  | 
|  28.11.2008, 19:21 | #4 | 
| Участник | |
|  | 
|  28.11.2008, 20:02 | #5 | 
| Заноза в заднице | 
			
			В целом, конечно право имеет, но есть вопросы: 1. "SOFTWARE\\Microsoft\\MSCRM" - разве не хард-код? Здесь намного правильнее было бы создать центральную консоль управления плагинами, в которой отдельными полями хранить данные о строке подключения и прочих разных параметрах. Данные об этом уместно складывать в веб-конфиг - он для того и предназначен. А лезть в реестр может только тот, у кого есть соответствующие права. У нас, например, правила безопасности таковы, что кто попало не имеет прав на читку реестра, даже если он админ в системе CRM. 2. Использование CrmService вызывает отторжение что-ли, я не пойму? С помощью CrmService можно выполнить все те же операции, приемлемыми для системы методами. К тому же, я полагаю, что скорость обработки будет гораздо быстрее. 
				__________________ Лень мудрого человека - это необходимое средство нейтрализации кипучей активности руководящих им дураков! | 
|  | 
|  28.11.2008, 22:18 | #6 | 
| Moderator | 
			
			Да незачем ее брать! Есть CrmService которым надо пользоваться! Помню помню, что для весьма специфичных задач он не подходит, но, как я уже говорил большинство из них преодолимо.
		 
				__________________ http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.   MS Certified Dirty Magic Professional | 
|  | 
|  30.11.2008, 01:25 | #7 | 
| Чайный пьяница | Цитата: Насчёт скорости - 100% быстрее будет работать прямой запрос, потому что звено короче на 1 - на веб сервис. Объясню, почему я ушёл от работы с веб сервисами. Механизм джоинов - конечно при работе с веб сервисами есть - через фетч и линкд ентити и прочее, но оно настолько громоздкое и нетривиальное, что для меня - как разработчика было проще написать прямой запрос к базе. | 
|  | 
|  30.11.2008, 15:03 | #8 | 
| Moderator | 
			
			С этим согласен - механизм построения запросов у Microsoft неимоверно убогий. Кто работал с Oracle TopLink меня поймет...
		 
				__________________ http://fixrm.wordpress.com, снятие/наведение порчи. Быстро, дорого, гарантия.   MS Certified Dirty Magic Professional | 
|  |