Как скачать установщик MSI с аргументом для идентификатора пользователя
У меня есть приложение.NET C#, обернутое в установщик MSI - "myprogram.exe". У меня есть веб-сайт PHP и определенная страница, где пользователь может скачать программу по ссылке.
Я хотел бы иметь возможность отслеживать определенные события в приложении.NET. Например - "Программа открыта".
На мой сервер легко отправлять события, однако как мне получить идентификатор пользователя с сервера php, чтобы я мог знать, какой пользователь что делал в приложении.NET?
Я думал о передаче аргумента (идентификатора пользователя) установщику MSI, но не смог найти путь к этому.
Как связать между идентификатором пользователя PHP и приложением.NET?
Пояснение -
Многие люди предлагали использовать систему входа в систему для связи между сервером и приложением.
Это действительно самое простое решение, однако на моем веб-сайте я не вынуждаю пользователя войти в систему, чтобы загрузить приложение (и не запрашиваю данные для входа в приложение.NET - это необязательно). Если нам не нужно запрашивать данные для входа, я думаю, что нет, пользовательский опыт будет намного лучше (гораздо меньше шагов для использования приложения) - у пользователя будет больше шансов загрузить и использовать приложение Desktop.
Учтите, что текущий поток -> веб-страница - загрузка клика - запуск - использование приложения (занимает 10 секунд)
При входе в систему -> Веб-страница - Зарегистрироваться (подтвердить адрес электронной почты?) - Перенаправить - Загрузить Нажмите - Запустить - Вход в приложение - Использовать приложение (пользователю требуется 60-120 секунд)
3 ответа
Вход из программы
Лучший способ - позволить пользователю войти в систему с теми же учетными данными в вашей программе. Таким образом, ваша программа может использовать безопасную аутентификацию OAuth2 для взаимодействия с вашим внутренним API. Это также делает прозрачным для пользователя, что программа общается с Интернетом.
Включить идентификатор пользователя в имя файла
Другой способ - добавить идентификатор пользователя к имени файла программы установки во время загрузки и извлечь его при запуске программы установки. Вам нужно будет проверить, позволяет ли это ваш установщик. Кроме того, делайте это только в том случае, если вы используете UUID или что-то подобное, поскольку вы не хотите, чтобы пользователь угадывал другие идентификаторы.
App.config
Третий вариант - добавить идентификатор пользователя к App.config
файл. Есть два способа сделать это:
- Создайте свой MSI с
App.config
без сжатия добавьте настройку идентификатора пользователя с фиксированным UUID. Ваш скрипт PHP может найти UUID и заменить его в двоичном файле MSI перед отправкой пользователю. Смотрите фрагмент кода под MST-преобразованием. - Сборка.msi по требованию с обычаем
App.config
, Это будет работать только в том случае, если ваш веб-сервер работает в Windows или у вас есть удаленный сервер сборки Windows, который может выполнить эту работу.
MST преобразование
Вы также можете использовать MST-преобразование и использовать тот же трюк двоичной замены, который я объяснил для пункта 1 в App.config.
Для обоих вариантов вы можете использовать PHP-скрипт, который использует бинарно-безопасные функции для замены значений в установщике и отправляет файл пользователю для загрузки:
<?php
$userId = // TODO get userId from the session or database
$data = file_get_contents("./my-installer.msi");
// I would use UUID's for template and userId, this way the size of the installer remains the same after replace
$data = str_replace("{fe06bd4e-4bed-4954-be14-42fb79a79817}", $userId, $data);
// Return the file as download
header("Cache-Control: public"); // needed for i.e.
header('Content-Disposition: attachment; filename=my-installer.msi');
header('Content-Type: application/x-msi');
header("Content-Transfer-Encoding: Binary");
echo $data;
?>
Серийный номер
Последний способ, о котором я могу подумать, - это позволить программе запрашивать серийный номер при первом запуске и позволить вашему веб-сайту генерировать уникальный серийный номер для каждого пользователя.
Хм, пожалуйста, обратите внимание, очень вероятно, что это не то, что вы хотите сделать. Тем не менее, я объясню пару способов сделать это..
Использование файлов MST с MSI:
Вы можете создавать MST-файлы со свойством user-id и генерировать их для каждого пользователя, когда они загружают MSI, и заставляют их устанавливать MSI с преобразованием:
msiexec -i c:\temp\The.msi transforms=c:\temp\YourPerso.mst
См. Дополнительную информацию здесь: Установите преобразование с помощью командной строки.
Вы видите, что файлы MST часто используются в крупных организациях, где все MSI имеют файлы MST со встроенными серийными номерами и т. Д.
Для создания MST-файла вам необходимо скачать и установить Microsoft Orca Tool, входящую в состав Microsoft Windows SDK.
Откройте Orca и создайте файл MST из файла MSI. В основном вы открываете MSI-файл, переходите к таблице "Свойство", там вы видите список параметров. Обратите внимание, что в файле MSI вы увидите параметры, которые требуют значения по умолчанию.
Прежде чем добавлять / изменять параметры, создайте новое Преобразование, щелкнув в меню "Преобразование" -> "Новое преобразование".
После этого вы можете изменить параметры или добавить новые, как вы хотите. Когда вы закончите изменения параметров, используйте функцию "Generate Transform" в меню "Transform" для генерации MST-файла.
Если вы затем откроете файл MST с помощью HexEditor, вы увидите только что добавленное свойство:
Вы можете редактировать файл для каждой загрузки, просто редактируя значение, например:
Конечно, вы можете (и, вероятно, должны) сделать это надлежащим образом, используя API-интерфейс WindowsInstaller.Installer. Вот пример:
private function createTransform(mstfile, msi, config)
writeLog InfoLog, "Generating transform " & mstfile
dim vars: set vars = configvars(config)
dim createPropertyTable: createPropertyTable = "create table `Property` " & _
"(`Property` char(72) not null, `Value` longchar localizable " & _
"primary key `Property`)"
dim addProperty: addProperty = "insert into `Property` (`Property`, `Value`) values (?, ?)"
dim updateProperty: updateProperty = "update `Property` set `Value` = ? where `Property` = ?"
dim wi: set wi = createObject("WindowsInstaller.Installer")
dim base: set base = wi.openDatabase("base.msi", msiOpenDatabaseModeCreate)
base.openview(createPropertyTable).execute
dim tgt: set tgt = wi.openDatabase("tgt.msi", msiOpenDatabaseModeCreate)
tgt.openview(createPropertyTable).execute
dim props: set props = createObject("scripting.dictionary")
dim view: set view = msi.openView("select `Property`, `Value` from `Property`")
view.execute
dim record: set record = view.fetch
while not record is nothing
props(record.stringdata(1)) = true
base.openview(addProperty).execute record
tgt.openview(addProperty).execute record
set record = view.fetch
wend
set record = wi.createRecord(2)
dim prop
for each prop in properties_
on error resume next
dim val: val = expand(vars, prop(DepPropertyValueIdx))
if err then
writeLog ErrorLog, err.description
exit function
end if
on error goto 0
writeLog InfoLog, "Property " & prop(DepPropertyNameIdx) & "=" & val
if props.exists(prop(DepPropertyNameIdx)) then
record.stringdata(2) = prop(DepPropertyNameIdx)
record.stringdata(1) = val
tgt.openview(updateProperty).execute record
else
record.stringdata(1) = prop(DepPropertyNameIdx)
record.stringdata(2) = val
tgt.openview(addProperty).execute record
end if
next
if not tgt.generateTransform(base, mstfile) then
writeLog ErrorLog, "Failed to create transform"
exit function
end if
tgt.createTransformSummaryInfo msi, mstfile, 0, 0
createTransform = true
end function
Подсказка: чтобы сделать это с помощью управляемого кода, лучше всего использовать Microsoft.Deployment.WindowsInstaller.dll
это доступно как часть http://wix.codeplex.com/
Создайте MSI для каждого пользователя:
ИМХО, было бы намного проще сделать это с помощью Nullsoft (WiX, InstallShield, INNO и т. Д.) И создать MSI для каждого пользователя. Для этого вы должны встраивать уникальный идентификатор пользователя, например, в скрипт nsi, и запускать сборку MSI для каждой загрузки. Во время установки уникальный идентификатор пользователя будет храниться в файле, разделе реестра и т. Д. Я предлагаю вам попробовать, используя этот редактор NSIS Wizard, чтобы быстро создать базовый сценарий установки NSI и построить MSI с помощью командной строки: makensis.
Примечание. Хотя "Включение идентификатора пользователя в имя файла MSI" проще, чем создание MSI для каждого пользователя, пользователи могут легко изменить имя файла. Гораздо менее вероятно, что пользователь будет проверять MSI с помощью Orca, чтобы найти встроенный идентификатор пользователя.
Самый простой и логичный способ:
На мой сервер легко отправлять события, однако как мне получить идентификатор пользователя с сервера php, чтобы я мог знать, какой пользователь что делал в приложении.NET?
Сделайте то, что @Jhuliano Moreno, а затем @WouterHuysentruit рекомендовал:
Когда ваше приложение запускается в первый раз, просто сделайте вход пользователя в программу, используя его учетные данные на сайте, и запишите его идентификатор пользователя в файле конфигурации, разделе реестра или записи базы данных. По сути, создание куки, чтобы вы знали их в следующий раз, когда откроет программу, или заставили их войти в систему каждый раз.
Когда файл вызывается, отправьте параметр UserID, если вы используете MVC-фреймворк в вашем PHP, вам понадобится новый контроллер, который получает MSI-файл и переименовывает его в name-userID.exe, а затем возвращает файл для загрузки. через браузер.