Время прочтения: 3 мин.

Именно с такой задачей мне пришлось столкнуться в работе: подстановка в заранее имеющийся шаблон различных данных, в том числе, информации об объекте аудиторской проверки. Так как требовалось внедрить данную возможность в уже существующий веб-интерфейс, разработка велась на ASP.NET с серверным кодом на C#.

Первым шагом в решении данной задачи, конечно же, является выбор библиотеки для работы с данным форматом файлов. Компанией Microsoft была разработана специальная библиотека для работы с офисными приложениями – Microsoft.Office.Interop, в связи с чем возникает соблазн использовать именно её. И, действительно, это хороший выбор для большинства задач, однако существует маленькая загвоздка: для её использования необходимо, чтобы пакет Microsoft Office был установлен на сервере приложений.

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

Подставляя в документ автоматически сгенерированный текст, крайне уместно было бы защитить его от изменения, ведь именно корректность текста документа и является конечной целью нашей задачи. Для этого необходимо защитить текст шаблона документа с помощью встроенных средств Microsoft Word. На вкладке рецензирование выбрать пункт “Ограничить редактирование”, отметить “галочкой” “Ограничения на редактирование” и в пункте “Исключения” выделить те части текста, которые пользователям будет разрешено отредактировать (если таковые имеются). После этого выбрать пункт “Включение защиты”, нажав кнопку “Да, включить защиту” и задать пароль (если ваша версия отлична от Microsoft Word 2016, алгоритм действий может отличаться).

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

//класс для работы с документом
public class WordDocument
{
	Xceed.Words.NET.DocX doc;
	string ProtectPassword;
	private string FileName;
	//конструктор для инициализации экземпляра класса
	public WordDocument(string TemplatePath, string password)
	{
		//создадим временный файл с именем tmpfile, куда положим итоговый документ
		var tmpfile = Path.GetTempFileName();
		FileName = tmpfile;
		//получим шаблон файла, хранящийся на сервере
		doc = DocX.Load(TemplatePath);
		//получим пароль файла
		ProtectPassword = password;
	}
	//Найти и заменить текст в документе
	public void FindAndReplaceInDoc(string find, string replace) 
	{
		if (doc == null)
			return;
		//снимем защиту с файла для редактирования защищённых областей
		doc.RemoveProtection();
		//подставим необходимый текст
		doc.ReplaceText(find, replace);
		//восстановим пароль на файл
		doc.AddPasswordProtection(EditRestrictions.readOnly ,ProtectPassword);
	}
	//Сохранение документа во временный файл для последующей сериализации
	public bool SaveFile(string FileName)
	{
		if (doc != null)
		{
			try
			{
				doc.SaveAs(FileName);
				this.FileName = FileName;
				return true;
			}
			catch
			{
				return false;
			}
		}
		return false;
	}
	//Сериализация документа
	public byte[] GetDocument()
	{
		if (SaveFile(FileName))
	             {
			byte[] FileBytes = File.ReadAllBytes(FileName);
			return FileBytes;
		}
		return null;
	}
}

После создания данного класса достаточно инициализировать экземпляр и заменить в нём искомое:

//получим пароль и путь к файлу на сервере
string password = GetPassword(); 
string path = GetTemplatepath();
//получим информацию, которую мы ходим подставить в документ
string new_text = GetData(); 
//инициализируем документ с помощью шаблона и пароля
WordDocument doc = new WordDocument (path, password);
//Подставляем новый текст
doc. FindAndReplaceInDoc(“%template_text%”, new_text); 

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

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

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