РЭДЛАЙН
Лучшие решения для Вас и Вашего бизнеса!
На нашем сайте вы можете получить информацию о веб-разработке, обслуживании и продвижении сайта. Интернет-маркетинге. SEO (поисковой оптимизации). Контекстной и медийной рекламе в Интернете. SMM. Регистрации доменов и хостинговых услугах. И современном дизайне сайтов. Вообщем того что касается веб-разработки, а также много другой полезной информации из мира интернета, бизнеса и интернет-технологий...
Создаем доступные и современные сайты, которые работают! Обслуживаем и эффективно продвигаем интернет-проекты с 2006 года!
Главная Программирование ASP.NET MVC: История одного проекта Обработка ошибок (часть 8)


ASP.NET MVC: История одного проекта Обработка ошибок (часть 8)

Содержание

ASP.NET MVC: История одного проекта "Готовимся к старту" (часть 1)
ASP.NET MVC: История одного проекта "Всё ради данных" (часть 2)
ASP.NET MVC: История одного проекта "Шаблоны и внешний вид" (часть 3)
ASP.NET MVC: История одного проекта "Еще немного классов" (часть 4)
ASP.NET MVC: История одного проекта "UI - всё для пользователя" (часть 5)
ASP.NET MVC: История одного проекта "UI - Добавление экспоната" (часть 6)
ASP.NET MVC: История одного проекта "UI - Редактирование экспоната" (часть 7)
ASP.NET MVC: История одного проекта "Обработка ошибок" (часть 8)
ASP.NET MVC: История одного проекта "Фильтрация" (часть 9)
ASP.NET MVC: История одного проекта "Поиск" (часть 10)
ASP.NET MVC: История одного проекта "Облако тегов" (часть 11)
ASP.NET MVC: История одного проекта "Главная страница" (часть 12)

Палки в колеса

ASP.NET MVC Framework умеет многое. Если вам что-то не нравится, или вы просто хотите реализовать что-либо по-другому, MVC Framework не станет "вставлять палки в колеса", а наоборот предоставит дружелюбный интерфейс. Сегодня поговорим про обработку ошибок. Будут описаны четыре с половиной способа реализации, от простого до продвинутого. Выбирать вам предстоит вам, основываясь на конкретном проекте, или на личных предпочтениях.

Вариант первый "Как два пальца об асфальт"

Самый наверное простой способ использовать HandleErrorAttribute, который любезно предоставили разработчики фреймворка. Но для начала я хочу показать, какая разница и для его нужна обработка ошибок. Никто не застрахован от ошибок, и даже программисты. :) Для этого давайте подготовим проект к выдачи ошибки при открытие главной страницы. Специально вызовим ошибку:


public ActionResult Index() {
	throw new ArgumentException("Специальная ошибка для теста");
	//return View();
}

Запустим сайт и увидим ошибку ("некрасивая" форма отображения):

Не очень приятная картина, не правда ли? Но всё меняется когда приходят мы поставим вышеуказанный атрибут (можно над методом, а можно охватить все методы поставив его на контроллером). Атрибут имеет параметр ViewName, который, как вы понимаете принимает название представления для перенаправления при возникновении ошибки. Если вы поставите атрибут над контролером, то перенаправление будет всегда на одну страницу. А если над методом, то у каждого из них может быть своя страница с ошибкой. Я поставил над контролером, а значит по умолчанию перенаправление будет на представление Error:


[HandleError() ]
public class SiteController : Controller {
	/// много букв
}

Теперь запустим... Опаньки! не сработал! Ах, чёрт побери, совсем забыл включить обработку ошибок в файле конфигурации (web.config). Итак, чтобы заработал атрибут, надо включить в секцию System.Web строку CustomErrors:


<system.web>
	<!-- много букв-->

	<customErrors mode="On" />

	<!-- много букв-->
</system.web>

Запускаем еще раз! Ура! Вот что я увидел:

Пожалуй немного поясню. По умолчанию в проекте MVCApplication в папке Views/Shared создается представление Error.cshtml. Это как раз то представление (View), куда делает перенаправление при ошибке атрибут HandleError. Я это представление немного изменил:


@model System.Web.Mvc.HandleErrorInfo
@{
	ViewBag.Title = "Error";
}
<h2>
	Ошибка
</h2>
@Html.ShowAlert(@"В результате выполнения запроса 
возникла непредвиденная ситуация. Информация о 
случившемся уже направлена администраторам системы. 
Проблема будет устранена в кратчайшие сроки.
Приносим вам свои извинения за возможно доставленные неудобства.")
<p>
	С уважением, Администрация</p>

Именно это вы и увидели на предыдущей картинке. Уже не плохо, но дальше - лучше.

Вариант второй "Немного летмотивов"

Поехали дальше... Я убрал атрибут и настройку в файле конфигурации web.config для чистоты эксперимента. Контролеры в MVC - это лейтмотив фреймворка. По умолчанию контролеры, которые вы создаете или будете создавать в своем проекте наследуются от базого абстрактного класса Controller:


public abstract class Controller : 
	ControllerBaseIActionFilterIAuthorizationFilterIDisposableIExceptionFilterIResultFilter {
///...много букв
}

Нам интересен тот факт, что у этого базового контролера есть виртуальный метод OnException:


//
// Summary:
//     Called when an unhandled exception occurs in the action.
//
// Parameters:
//   filterContext:
//     Information about the current request and action.
protected virtual void OnException(ExceptionContext filterContext);

Из описания понятно, что предназначен отслеживать исключения в контролере. А раз он виртуальный, то его можно переопределить в своём контролере, например, следующим образом:


protected override void OnException(ExceptionContext filterContext) {
	var controllerName = filterContext.RouteData.Values["controller"as String;
	var actionName = filterContext.RouteData.Values["action"as String;
	var model = new HandleErrorInfo(
		filterContext.Exception, 
		controllerName, 
		actionName);
	var result = new ViewResult {
		ViewName = "error",
		MasterName = string.Empty,
		ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
		TempData = filterContext.Controller.TempData
	};
	filterContext.Result = result;
 
	// сконфигурируем отправляемый ответ
	filterContext.ExceptionHandled = true;
	filterContext.HttpContext.Response.Clear();
	filterContext.HttpContext.Response.StatusCode = 500;
	filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}

Результатом поделанных махинаций действий будет представление, обратите внимание на жирную строку... Правильно! Всё то же представление (Error.cshtml) об ошибке (назовем его " красивое"). Уже совсем другой компот, потому что появилась какая-то "управляемость" процессом.

Вариант третий "Место встречи изменить нельзя"

Чтобы не писать в каждом контролере один и тот же код на обработку исключений можно сделать немного интереснее. В файле Global.asax в методе Application_Error написать код один раз, например так:


private void Application_Error(Object sender, EventArgs e) {
	var exception = Server.GetLastError();
	if (exception == null)
		return;
 
	//  ваша реализация обработки ошибки
	// вплоть до отправки ее на электронную почту
	// администратора системы
 
	// очищаем ошибку
	Server.ClearError();
 
	// перенаправляем пользователя на другую страницу
	// созданную специльно для этого.
	Response.Redirect("site/feedback");
}

Строка выделенная жирным перенаправит пользователя на "правильную" страницу в зависимости от типа ошибки, это как пример. Вы можете создать много таких специализированных страниц.

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

Вариант четверный "Любимый"

Я всегда использую этот вариант. Он немного посложнее, но целиком оправдывает свою сложность. Итак, первым делом я создаю новый контролер ErrorController. Он небольшой я приведу его весь:


public class ErrorController : Controller
{
	public ActionResult General(Exception exception) {
		return View("Exception", exception);
	}
 
	public ActionResult Http404() {
		return View("404");
	}
 
	public ActionResult Http403() {
		return View("403");
	}
 
	public ActionResult ExhibitNotFound() {
		return View();
	}
}

Также создаю все указанные представления (View) для методов. ExhibitNotFound.cshtml, 404.cshtml и 403.cshtml содержат просто текст с информацией, что "экспонат не найден","страница не найдена" или "доступ ограничен" соответственно, а General ключевое представление, поэтому покажу его полностью:


@model Exception
@{
	ViewBag.Title = "Exception";
	Layout = "~/Views/Shared/_LayoutExtended.cshtml";
}
<h2>
	Ошибка сайта</h2>
<p style="font-size1.2emcolorRedfont-weightbold;">
	Сообщение об ошибке уже отправлено разработчикам. Надеемся на ваше понимание.</p>
<p style="font-weightbold;">@Model.Message</p>
<p>
	Вы можете:</p>
<ul>
	<li>Перейти на главную @Html.ActionLink("страницу""index""site"). </li>
	<li>Сообщить о том, что Вы искали или при каких условиях появилась этот ошибка. Напишите
		разработчикам @Html.ActionLink("сообщение""feedback""site")</li></ul>
<fieldset style="font-size.85em;">
	<legend>Информация для разработчиков</legend>
	@Html.Raw(@Model.StackTrace.ToString())
</fieldset>

После этого я в Global.asax пишу метод Application_Error примерно так:


protected void Application_Error() {
#if !DEBUG
	var exception = Server.GetLastError();
	var httpException = exception as HttpException;
	Response.Clear();
	Server.ClearError();
	var routeData = new RouteData();
	routeData.Values["controller"] = "Error";
	routeData.Values["action"] = "General";
	routeData.Values["exception"] = exception;
	Response.StatusCode = 500;
	if (httpException != null) {
		Response.StatusCode = httpException.GetHttpCode();
		switch (Response.StatusCode) {
		case 403:
			routeData.Values["action"] = "Http403";
			break;
		case 404:
			routeData.Values["action"] = "Http404";
			break;
		}
	}
	Response.TrySkipIisCustomErrors = true;
	IController errorsController = new ErrorController();
	HttpContextWrapper wrapper = new HttpContextWrapper(Context);
	var rc = new RequestContext(wrapper, routeData);
	errorsController.Execute(rc);
#endif
 
}

Если запустить мой проект сейчас, то я увижу такою картинку:

Мне кажется, это более интересная реализация обработки ошибок. Причем стек можно отображать только при условии, если пользователь имеет права администратора. А самое главное, что теперь можно немного усовершенствовать полученный результат и записывать ошибки в базу данных, создать, своего рода, журнал изменений (Logs), в который можно писать не только ошибки (Errors), но и предупреждения (Warnings), и просто информацию (Information) о действиях пользователя или статусов системы.

Вариант четвертный с половиной или новый класс (Log)

Создаю просто класс, который будет использоваться при работе с логами:


public class Log {
	public Log() { }
	/// <summary>
	/// Создает экземпляр записи в журнале документов
	/// </summary>
	/// <param name="message">текст сообщения</param>
	public Log(string message) {
		this.Message = message;
		this.CreatedAt = DateTime.Now;
	}
 
	[Key]
	[Display(Name = "Идентификатор")]
	public int Id { getset; }
 
	/// <summary>
	/// Текст сообщения
	/// </summary>
	[Required]
	[Display(Name = "Текст сообщения о событии")]
	[StringLength(500)]
	public string Message { getprivate set; }
 
	/// <summary>
	/// Дата выполнения операции
	/// </summary>
	[Required]
	[Display(Name = "Выполнено")]
	public DateTime CreatedAt { getprivate set; }
 
	/// <summary>
	/// Имя пользователя
	/// </summary>
	[Required]
	[ Display(Name = "Автор")]
	[ StringLength(50)]
	public string UserName { getset; }
}

А теперь при помощи MvcScaffolding создаю репозиторий:

PM> Scaffold Repository Log -DbContextType MuseumContext
Added 'Logs' to database context 'Calabonga.Mvc.Humor.Engine.MuseumContext'
Added repository 'Models\LogRepository.cs'
PM>

 А теперь придется немного поправить код в репозитории, потому что это у меня не очень обычный репозиторий. Добавим и удалим некоторые методы придеживаясь такого интерфейса:


public interface ILogRepository {
	IQueryable<Log> All { get; }
	Log Find(int id);
	void Log(string message, bool sendNotify);
	void Log(string messageformat, string param0);
	void Log(string messageformat, string param0, bool sendNotify);
	void Log(string messageformat, string param0, string param1);
	void Log(string messageformat, string param0, string param1, bool sendNotify);
	void Delete(int id);
	void Clear();
}

Вы можете придумать свою реализацию этого интерфейса, да и, собственно говоря, и сам интерефейс тоже можете себе придумать сами. А мне остается только добавить запись в журнал в методе Application_Error изпользуя новый LogRepository (жирным шрифтом):


protected void Application_Error() {
#if !DEBUG
	var exception = Server.GetLastError();
	var httpException = exception as HttpException;
	Response.Clear();
	Server.ClearError();
	var routeData = new RouteData();
	routeData.Values["controller"] = "Error";
	routeData.Values["action"] = "General";
	routeData.Values["exception"] = exception;
	Response.StatusCode = 500;
	if (httpException != null) {
		Response.StatusCode = httpException.GetHttpCode();
		switch (Response.StatusCode) {
			case 403:
				routeData.Values["action"] = "Http403";
				break;
			case 404:
				routeData.Values["action"] = "Http404";
				break;
		}
	}
	Response.TrySkipIisCustomErrors = true;
	IController errorsController = new ErrorController();
	LogRepository logger = new LogRepository();
	logger.Log(string.Concat("ОШИБКА: ", exception.Message));
HttpContextWrapper wrapper = new HttpContextWrapper(Context);
	var rc = new RequestContext(wrapper, routeData);
	errorsController.Execute(rc);
#endif
 
}

У вас наверное возникнет вопрос, почему именно так? Потому что если возникает ошибка или "выстреливает" какое-нибудь исключение, то получить ILogRepository через Dependency Injection уже не получится, поэтому я создаю экземпляр класса и использую его напрямую. Но в контролерах я буду получать именно ILogRepository через Dependency Injection в конструкторе, как и положено.

И напоследок

Я обычно в методах, которые должны каким-то образом реагировать на ошибки и исключения писал TODO, например как этом методе:


public ActionResult Show(int id) {
	Exhibit exh = exhibitRepository.Find(id);
	if (exh != null) {
		return View(new ShowExhibitViewModel(exh));
	}
	// TODO: пока при отсутвии обработки ошибок
	// буду перекидывать на страницу списка
	return RedirectToAction("index");
}

После того как заработала система обработки ошибок, я могу все методы поправить включив обработку в методы. Например для предыдущего метода сделаю так:


public ActionResult Show(int id) {
	Exhibit exh = exhibitRepository.Find(id);
	if (exh != null) {
		return View(new ShowExhibitViewModel(exh));
	}
	return RedirectToAction("http404""error");
}

Таким образом, пользователь получит правильное уведомление о том что такой записи в базе нет.

Заключение

Я сделал на странице администрирования сайта ссылку на просмотр журнала изменений, которая будет отобржать логи постранично. Надеюсь, это у вас не вызовет затруднений, поэтому я не буду описывать эти действия, а покажу как это выглядит у меня:

И, как я обещал в комментариях к предыдущей статье, вот ссылка на скачивание проекта в текущей сборке. Спасибо за внимание - пишите комментарии.

Подробнее: http://feedproxy.google.com/~r/blogmusor/~3/dkUT5gO-ZAQ/83

ASP.NET MVC: История одного проекта Обработка ошибок (часть 8) | | 2012-09-13 08:38:46 | | Программирование | | Содержание ASP.NET MVC: История одного проекта Готовимся к старту (часть 1)ASP.NET MVC: История одного проекта Всё ради данных (часть 2)ASP.NET MVC: История одного проекта Шаблоны и внешний вид | РэдЛайн, создание сайта, заказать сайт, разработка сайтов, реклама в Интернете, продвижение, маркетинговые исследования, дизайн студия, веб дизайн, раскрутка сайта, создать сайт компании, сделать сайт, создание сайтов, изготовление сайта, обслуживание сайтов, изготовление сайтов, заказать интернет сайт, создать сайт, изготовить сайт, разработка сайта, web студия, создание веб сайта, поддержка сайта, сайт на заказ, сопровождение сайта, дизайн сайта, сайт под ключ, заказ сайта, реклама сайта, хостинг, регистрация доменов, хабаровск, краснодар, москва, комсомольск |
 
Дайджест новых статей по интернет-маркетингу на ваш email
Подписаться

Продающие сайты "под ключ"!

Наши сайты зарабытывают вам деньги. Landing-page. Эффективные продающие сайты точно в срок и под ключ! Всего от 28300 рублей
Подробнее...

Интернет-магазины и каталоги "под ключ"!

Эффективные и удобные инструменты торговли (электронной торговли) "под ключ". Продают, даже когда вы спите! Всего от 52700 рублей
Подробнее...

Комплексный интернет-маркетинг и продвижение сайтов

Максимальную эффективность дает не какой-то конкретный метод, а их комбинация. Комбинация таких методов и называется комплексным интернет-маркетингом. Всего от 10000 рублей в месяц
Подробнее...

Реклама в Yandex и Google

Контекстная реклама нацелена лишь на тех пользователей, которые непосредственно заинтересованы в рекламе Ваших услуг или товаров. Всего от 10000 рублей в месяц
Подробнее...

Social media marketing (SMM) — продвижение в социальных медиа

Реклама в VK, Однокласcниках и на Mail.ru Создание, ведение и раскрутка групп и реклама ВКонтакте и Facebook. Всего от 10000 рублей в месяц
Подробнее...

Приглашаем к сотрудничеству рекламные агентства и веб-студии!

Внимание Акция! Приглашаем к сотрудничеству рекламные агентства и различные веб-студии России! Индивидуальные и взаимовыгодные условия сотрудничества.
Подробнее...

Ускоренная разработка любого сайта от 5 дней!

Внимание Акция! Ускоренная разработка любого сайта! Ваш сайт будет готов за 5-10 дней. Вы можете заказать разработку любого сайта "под ключ" за 5-10 рабочих дней, с доплатой всего 30% от его стоимости!
Подробнее...

Ждем новых друзей!

Внимание Акция! Ждем новых друзей! Скидка 10% на услуги по созданию и(или) обслуживанию вашего сайта при переходе к нам от другого разработчика.
Подробнее...

Приведи друга и получи скидку!

Внимание Акция! Приведи друга и получи скидку! Скидка 10% на услуги по созданию и(или) обслуживанию вашего сайта, если клиент заказавший наши услуги, пришел по Вашей рекомендации.
Подробнее...

1 2 3 4 5 6 7 8 9

Новые статьи и публикации



Мы создаем сайты, которые работают! Профессионально обслуживаем и продвигаем их , а также по всей России и ближнему зарубежью с 2006 года!

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

Заявка
Позвоните или оставьте заявку на сайте.


Консультация
Обсуждаем что именно Вам нужно и помогаем определить как это лучше сделать!


Договор
Заключаем договор на оказание услуг, в котором прописаны условия и обязанности обеих сторон.


Выполнение работ
Непосредственно оказание требующихся услуг и работ по вашему заданию.


Поддержка
Сдача выполненых работ, последующие корректировки и поддержка при необходимости.

Остались еще вопросы? Просто позвоните и задайте их специалистам
с 2:30 до 11:30 по Мск, звонок бесплатный
Или напишите нам в WhatsApp
с 9:30 до 18:30 по Хабаровску
Или напишите нам в WhatsApp
Веб-студия и агентство комплексного интернет-маркетинга «РЭДЛАЙН» © 2006 - 2024

Профессиональная Веб-разработка. Создание сайтов и магазинов "под ключ" , а также по всей России и зарубежью. Продвижение и реклама. Веб-дизайн. Приложения. Сопровождение. Модернизация. Интеграции. Консалтинг. Продвижение и реклама. Комплексный Интернет-маркетинг.

Оставьте заявку / Задайте вопрос

Нажимая на кнопку ОТПРАВИТЬ, я даю согласие на обработку персональных данных
×

Заказать услугу

Нажимая на кнопку ОТПРАВИТЬ, я даю согласие на обработку персональных данных
×

Обратный звонок

Нажимая на кнопку ОТПРАВИТЬ, я даю согласие на обработку персональных данных
×

Подписка на дайджест новостей

Нажимая на кнопку ОТПРАВИТЬ, я даю согласие на обработку персональных данных
×

Заказать услуги со скидкой \ Бесплатная консультация







КАКИЕ УСЛУГИ ВАС ИНТЕРЕСУЮТ?

КАКИЕ ДОПОЛНИТЕЛЬНЫЕ УСЛУГИ ПОТРЕБУЮТСЯ?

Нажимая на кнопку ОТПРАВИТЬ, я даю согласие на обработку персональных данных
×

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

Что нужно сделать, чтобы заказать создание сайта у нас?

Ну для начала вам нужно представлять (хотя бы в общих чертах), что вы хотите получить от сайта и возможно каким вы хотите его видеть. А дальше все просто. Позвоните нам или оставьте заявку нашим менеджерам, чтобы они связались с Вами, проконсультировали и помогли определиться с подходящим именно Вам сайтом по цене, сроку, дизайну или функционалу. Если вы все ещё не уверены, какой сайт вам нужен, просто обратитесь к нам! Мы вместе проанализируем вашу ситуацию и определим максимально эффективный для вас вариант.

Быстрый заказ \ Консультация

Для всех тарифных планов на создание и размещение сайтов включено:

Комплексная раскрутка сайтов и продвижение сайта Комплексный подход это не просто продвижение сайта, это целый комплекс мероприятий, который определяется целями и задачами поставленными перед сайтом и организацией, которая за этим стоит. Время однобоких методов в продвижении сайтов уже прошло, конкуренция слишком высока, чтобы была возможность расслабиться и получать \ удерживать клиентов из Интернета, просто сделав сайт и не занимаясь им...

Комплексная раскрутка работает в рамках стратегии развития вашего бизнеса в сети и направлена

Быстрый заказ \ Консультация

ЭФФЕКТИВНОЕ СОПРОВОЖДЕНИЕ (ПОДДЕРЖКА, ОБСЛУЖИВАНИЕ) САЙТОВ

Полный комплекс услуг по сопровождению сайтаМы оказываем полный комплекс услуг по сопровождению сайта: информационному и техническому обслуживанию и развитию Интернет сайтов.

Передав свой сайт для поддержки в руки наших специалистов, Вы избавитесь от проблем, связанных с обновлением информации и контролем за работой ресурса.

Наша компания осуществляет техническую и информационную поддержку уже имеющихся сайтов. В понятие «поддержка сайтов» также входят услуги администрирования сайтов, обновления сайтов и их модернизация.

Быстрый заказ \ Консультация

Редизайн сайта и Адаптивный веб дизайн

Современный, технологичный, кроссбраузерный ... Профессиональный дизайн сайтов и веб-приложений

Редизайн сайта — создание нового дизайна сайта с целью улучшения внешнего вида, функциональности и удобства использования. Редизайн сайта – это способ преобразовать проект к извлечению из него максимальной отдачи и средств. В современном мире задачами редизайна является поднятие существующего сайта на новый уровень для внедрения новых технологий, при этом сохраняя многолетний сформировавшийся опыт и успешные решения компаний.

Адаптивный дизайн сайтов и веб-приложений

Все больше людей пользуются мобильными устройствами (телефонами, планшетами и прочими) для посещения Интернета, это не для кого уже не новость. Количество таких людей в процентном отношении будет только больше с каждым годом, потому что это удобно и по многим другим причинам.

На сегодняшний день адаптивный дизайн является стандартным подходом при разработке новых сайтов (или веб-приложений) и в идеале ваш сайт должен смотреться и функционировать так, как вы задумывали, на всём разнообразии устройств.

Быстрый заказ \ Консультация

Контекстная реклама в Яндекс и GoogleКонтекстная реклама - это эффективный инструмент в интернет маркетинге, целью которого является увеличение продаж. Главный плюс контекстной рекламы заключается в том, что она работает избирательно.

Реклама в поисковых системах Яндекс и Google. Профессиональная настройка рекламы и отслеживание эффективности!

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

Быстрый заказ \ Консультация

Скидка

1500 руб.
Заинтересовались услугами создания, обслуживания или продвижения вашей компании в Интернете?!
Получите 1500 руб.
за он-лайн заявку
Предложение ограничено.

После получения заявки с Вами свяжутся наши специалисты и уточнят все детали по интересующей вас услуге.
«Нажимая на кнопку "Получить скидку", я даю согласие на обработку персональных данных»
×
Получите 1500 рублей!
×
×