Безопасное использование заголовка HTTP IfModifiedSince в PCL библиотеках

от автора

Неожиданно связь прервалась Мы разрабатываем приложение под несколько платформ, всю платформо независимую часть создаем с помощью PCL, стараясь добиться максимального уровня пере использования компонентов. Для коммуникаций с сервером используется класс HttpWebRequest который реализует всю необходимую от транспортного уровня функциональность.

Недавно протокол был оптимизирован, в нем появилась возможность сократить объем передаваемых данных указывая горизонт актуальности. Реализована данная оптимизация с помощью обработки HTTP заголовка IfModifiedSince, однако у объекта HttpWebRequest в PCL не доступного свойство IfModifiedSince. Это не казалось проблемой заголовок был добавлен напрямую в коллекцию заголовков запроса.

request.Headers[HttpRequestHeader.IfModifiedSince] = timeStamp.ToString(); 

Протестировав решение на WindowsPhone приложении я убедился в его работоспособности, но все юнит тесты транспортного уровня выдали ошибки. Изучив проблему обнаружил, что реализация WebHeaderCollection для платформы Windows, не позволяет напрямую задавать этот заголовок и требует, чтобы разработчики использовали свойство HttpWebRequest.IfModifiedSince которое не доступно в сборках PCL.

Для решения этой я создал метод расширения для класса HttpWebRequest реализующий следующую логику работы:

При первом обращении к методу, пытаемся добавить заголовок в коллекцию заголовков запроса, если это не удается, с помощью отражения ищем у объекта запроса поле IfModifiedSince и создаем и кешируем делегат для установки значения свойства.

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

namespace System.Net { 	public static class NetExtensions 	{ 		private static Action<HttpWebRequest, DateTime> _setIfMofifiedSince; 		public static void SetIfModifiedSince(this HttpWebRequest request, DateTime value) 		{ 			Guard.NotNull(request);  			if (_setIfMofifiedSince != null) 			{ 				_setIfMofifiedSince(request, value); 				return; 			}  			try 			{ 				request.Headers[HttpRequestHeader.IfModifiedSince] = value.ToString(); 				return; 			} 			// ReSharper disable once EmptyGeneralCatchClause 			catch 			{ 			}  			var property = request.GetType().GetRuntimeProperty("IfModifiedSince"); 			if (property != null 				&& property.CanWrite) 			{ 				var method = property.SetMethod; 				if (method != null) 				{ 					_setIfMofifiedSince = (Action<HttpWebRequest, DateTime>)method.CreateDelegate(typeof(Action<HttpWebRequest, DateTime>)); 				} 			}  			if (_setIfMofifiedSince == null) 			{ 				throw new Exception("Unable to set IfModifiedSince"); 			}  			_setIfMofifiedSince(request, value); 		} 	} } 

Используя этот метод расширения код остается простым для чтения и понимания.

request.SetIfModifiedSince(timeStamp); 

ссылка на оригинал статьи http://habrahabr.ru/post/219809/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *