Restore Previous State of app on database migration failure (ClickOnce) - c#

I want to restore previous version of C# application published using ClickOnce, if database migration fails because database wont be latest and it will not support latest version of application.
Details
I am developing an app which will be used locally in remote areas where internet is not available. A person will update his/her app every once in a while by getting internet somehow and then will deploy the app on local network. From there every one will be able to get the updated version of app. What I want now is to use database migration using this app and if the app fails It should restore to previous version. I have already used FluentMigrator for database migration and have used ClickOnce to deploy the app. I have also gone through almost every link over here to see how can I do it. I now know that its not possible using ClickOnce. Can anybody tell me some other way or may be some kind of hack?. I am using ClickOnce because of its auto update feature so don't really want to lose that functionality now. Any help will be appreciated.

FluentMigrator keeps track of current version in the database. It also keeps track of latest version in the current app version. Run Migrator function and check if the latest version of Migration files in the current version is equal to the latest version stored in a database. If both are equal then Migration was successful. If they are not equal then you can run the cmd command to directly open (remove or backup) window of the control panel and go to the previous version. This is the best you can do to revert to the previous version using ClickOnce.
try {
new MigrationsWrapper(AppManager.ConnectionString).MigrateToLatestVersion();
}
catch (Exception ex)
{
}
LatestVersionNumber = new MigrationsWrapper(AppManager.ConnectionStringADO).LatestVersionNumber;
CurrentVersionNumber = new MigrationsWrapper(AppManager.ConnectionStringADO).CurrentVersionNumber;
if (LatestVersionNumber > CurrentVersionNumber) {
string applicationName = ConfigurationManager.AppSettings["ApplicationName"].ToString();
string uninstallString = GetUninstallRegistryKeyByProductName(applicationName);
if (uninstallString != string.Empty) {
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "/c " + uninstallString;
process.StartInfo = startInfo;
process.Start();
}
} else {
// Successfull
}

So, you want to run previous version of the app if some problem happen during execution.
I don`t know solution for ClickOnce, but there is analogue for it - Squirrel.
Bad news that Squirrel has no straight solution too, but it phisically stores previous version of app and you can run it and it works (I just checked it on my app).
So, there is a strategy:
Migrate to the squirrel (they have a tool for it)
in case of emergency - calc path to the stored previous version and run it. Relative path should be like "../app-1.1.1/myApp.exe"
But there is one thing to keep in mind. Squirrel stores previous version only if it upgraded app from it. There is no prev version after first install.
Good luck.

From the description the different versions of the application are sharing a single database. As a new version of the application goes live on the machine it needs to patch/migrate a shared database. If that fails the application doesn't install. Let's hope it fails without corrupting the database also.
There are clickonce events that can be hoocked into. Create a Custom Installer maybe.
https://msdn.microsoft.com/en-us/library/system.deployment.application.applicationdeployment_events.aspx
https://msdn.microsoft.com/en-us/library/system.deployment.application.applicationdeployment.aspx
Publishing ClickOnce Applications
https://msdn.microsoft.com/en-us/library/748fh114.aspx
Walkthrough: Creating a Custom Installer for a ClickOnce Application
https://msdn.microsoft.com/en-us/library/dd997001.aspx
Hope that's helpful.

Related

Installation of development and production versions on the same computer

I have a stable production version of software which always has version number "1.X.0". We don't have any testing environment so I created a development version with version number "1.X.Y" for testing purposes. I test this version on production computer before releasing new production version (1.X+1.0)
This works fine, there are safety measures in place so that they cannot get mixed up. I also created automatic update for both versions using
startInfo.Arguments = string.Format("/passive /norestart /i \"{0}\" TARGETDIR=\"{1}\"", msiPath, installDirectory);
installDirectory is different for production and development version.
The problem is this:
The upgrade code is the same for both versions. I don't want to switch between upgrade codes.
I also set RemovePreviousVersion to false, because I don't want to have version 1.X.0 removed, when installing version 1.X.Y.
Is it possible to have versions 1.X.0 and 1.X.Y on the same computer at the same time and when version 1.X.0 gets upgraded to version 1.X+1.0, only 1.X.0 is uninstalled? The same should apply for 1.X.Y version.
Or is there a better way to handle this?
Thank you
I would strongly recommend using a virtual machine to test installation and upgrades of software. If you have pro or enterprise versions of windows you already have access to HyperV. This has several advantages:
You have a known environment, either a clean windows install, or in combination with the software of your choice.
You can easily revert the VM to a previous known state.
You can keep multiple VMs or snapshots of different versions.
You can test different operating systems in a easy way.
You can limit memory and processor capacity without affecting your main workstation.
You can install network limiting tools without affecting your main workstation.
You can, and should, still run and test development builds of the software on your own workstation since this simplify debugging. While VMs are more appropriate when doing "release" tests.
I found the solution for having 2 or more different versions of the same software installed at the same time and updating them automatically.
First I find the version I am currently using with
var version = Assembly.GetExecutingAssembly().GetName().Version;
I then compare that to the version of .msi file which is in a update folder on server (there are production and development folders). If the .msi version is higher than installed version, the upgrade begins.
First I install the new software in the same folder using
startInfo.Arguments = string.Format("/passive /norestart /i \"{0}\" TARGETDIR=\"{1}\"", path, installDirectory);
var process = System.Diagnostics.Process.Start(startInfo);
process.WaitForExit();
Then I uninstall only the version I opened.
I find the product code of that specific version using below code (I found the code in Windows GUID or Application List answer and modified it a bit)
private string GetProductCode(string programName, string version)
{
StringBuilder sbProductCode = new StringBuilder(39);
int iIdx = 0;
while (
0 == MsiEnumProducts(iIdx++, sbProductCode))
{
Int32 productNameLen = 512;
StringBuilder sbProductName = new StringBuilder(productNameLen);
MsiGetProductInfo(sbProductCode.ToString(),
"ProductName", sbProductName, ref productNameLen);
if (sbProductName.ToString().Contains(programName))
{
Int32 installDirLen = 1024;
StringBuilder sbVersionString = new StringBuilder(installDirLen);
MsiGetProductInfo(sbProductCode.ToString(),
"VersionString", sbVersionString, ref installDirLen);
if (version.Contains(sbVersionString.ToString()))
{
return sbProductCode.ToString();
}
}
}
return null;
}
and run
startInfo.Arguments = string.Format("/passive /norestart /x \"{0}\"", productCode);
System.Diagnostics.Process.Start(startInfo);
At the end there are still 2 installed version of the softare and only one was updated.

Creating an auto updating Windows service [duplicate]

For the project I am working on, I am not allowed to use ClickOnce. My boss wants the program to look "real" (with an installer, etc).
I have installed Visual Studio 2012 Professional, and have been playing around with the InstallShield installer, and it definitely makes nice installers, but I can't figure out how to enable the application to "auto-update" (that is, when it starts up, checks to make sure that it is using the latest version).
I have been asked to make a tiny change to the code - switching an addition to a subtraction, and I don't really want people to have to uninstall the old version, and then have to reinstall the new version every time I make a small change like this.
How can I make the application check for updates, and install them? Or is this not possible (or not easy)?
There are a lot of questions already about this, so I will refer you to those.
One thing you want to make sure to prevent the need for uninstallation, is that you use the same upgrade code on every release, but change the product code. These values are located in the Installshield project properties.
Some references:
Auto update .NET applications
Auto-update library for .NET?
Auto update for WinForms application
Suggest a method for auto-updating my C# program
Automatic update a Windows application
I think you should check the following project at codeplex.com
http://autoupdater.codeplex.com/
This sample application is developed in C# as a library with the project name “AutoUpdater”. The DLL “AutoUpdater” can be used in a C# Windows application(WinForm and WPF).
There are certain features about the AutoUpdater:
Easy to implement and use.
Application automatic re-run after checking update.
Update process transparent to the user.
To avoid blocking the main thread using multi-threaded download.
Ability to upgrade the system and also the auto update program.
A code that doesn't need change when used by different systems and
could be compiled in a library.
Easy for user to download the update files.
How to use?
In the program that you want to be auto updateable, you just need to call the AutoUpdate function in the Main procedure. The AutoUpdate function will check the version with the one read from a file located in a Web Site/FTP. If the program version is lower than the one read the program downloads the auto update program and launches it and the function returns True, which means that an auto update will run and the current program should be closed. The auto update program receives several parameters from the program to be updated and performs the auto update necessary and after that launches the updated system.
#region check and download new version program
bool bSuccess = false;
IAutoUpdater autoUpdater = new AutoUpdater();
try
{
autoUpdater.Update();
bSuccess = true;
}
catch (WebException exp)
{
MessageBox.Show("Can not find the specified resource");
}
catch (XmlException exp)
{
MessageBox.Show("Download the upgrade file error");
}
catch (NotSupportedException exp)
{
MessageBox.Show("Upgrade address configuration error");
}
catch (ArgumentException exp)
{
MessageBox.Show("Download the upgrade file error");
}
catch (Exception exp)
{
MessageBox.Show("An error occurred during the upgrade process");
}
finally
{
if (bSuccess == false)
{
try
{
autoUpdater.RollBack();
}
catch (Exception)
{
//Log the message to your file or database
}
}
}
#endregion
The most common way would be to put a simple text file (XML/JSON would be better) on your webserver with the last build version. The application will then download this file, check the version and start the updater. A typical file would look like this:
Application Update File (A unique string that will let your application recognize the file type)
version: 1.0.0 (Latest Assembly Version)
download: http://yourserver.com/... (A link to the download version)
redirect: http://yournewserver.com/... (I used this field in case of a change in the server address.)
This would let the client know that they need to be looking at a new address.
You can also add other important details.
A Lay men's way is
on Main() rename the executing assembly file .exe to some thing else
check date and time of created.
and the updated file date time and copy to the application folder.
//Rename he executing file
System.IO.FileInfo file = new System.IO.FileInfo(System.Reflection.Assembly.GetExecutingAssembly().Location);
System.IO.File.Move(file.FullName, file.DirectoryName + "\\" + file.Name.Replace(file.Extension,"") + "-1" + file.Extension);
then do the logic check and copy the new file to executing folder
This is the code to update the file but not to install
This program is made through dos for copying files to the latest date and run your program automatically. may help you
open notepad and save file below with ext .bat
xcopy \\IP address\folder_share_name\*.* /s /y /d /q
start "label" /b "youraplicationname.exe"
These days you could use included in Windows 10 mechanism for app delivery called AppInstaller by packaging your app in MSIX bundle or package.
With it, you don't have to think about an installer (if your app doesn't use a lot of dependencies), background updating, and all of that. It's much better than ClickOnce, command-line usage works like a charm thanks to aliases, updates are non-obtrusive and could be used for background apps too.
The installation experience is much better too: a user just needs to click a button on HTML and Windows will install the app automatically.
It's not super-simple, I'd say more complicated than ClickOnce, but not as hard as Wix.
Official guide doesn't work with .NET Core or .NET 5 apps, so you can refer to this article, or to this great video, for example. This site also contains a lot of useful information.

System.ComponentModel.Win32Exception: Access is denied..... Error

I want to open one document file on our website. For that I write following code.
try
{
Process proc = new Process();
proc.StartInfo = new ProcessStartInfo(Server.MapPath("~/Quatation/PREMIUMQUOTATION1.doc"));
proc.Start();
}
catch (WebException we)
{
}
It runs locally very fine but web on web server it gives me an error like
System.ComponentModel.Win32Exception: Access is denied?
Please suggest, what should I do?
I had this problem when my .NET Target Framework was set to 4.5.2. I fixed it by changing the target framework version to 4.5. To do this using Visual Studio 2015, open Solution Explorer, right click on your solution and click Properties. The "Target Framework" should be set to ".NET Framework 4.5". Additionally, if you previously built with a target framework other than 4.5, you may have a <compiler> section in your web.config, and this may throw an error when you build. Just remove this section to fix the issue. Removing it should not cause any problems.
I wrote a short article about this here that has a couple other things to try that didn't work for me but might work for you.
Also check out This Stack Overflow answer which also helped numerous people with this error!
may be your SQL server is off
check it in services and start it
It sounds like you haven't changed the service logon user. You can do it from service control manager by right clicking the service and go to the Logon tab.
Then add user as Service Logon User
Or you can do it from the command line:
sc config ServiceName obj= Domain\user password= pass
Note the space between obj= and Domain\user it is not a typo. It is required. The same for password=.
My problem solve with this
In IIS Manage->Pool Application->Advance Setting->Identity
change to Custom Account and set Administrator User
Goto windows explorer and right click on the folder "~/Quatation/". Select properties and pick the Security tab to give permissions. In the case where your application pool under which the web application runs is using a domain account, you will need to give that specific domain account permission.
I faced the same issue while running my website from local IIS, after spending some time reading the project properties, found that, certain changes to the project properties were not saved...
Once it was saved, the error went away...
I got this error while I was working in visual studio 2017, using dotNet framework 4.5, in MVC project...
If you are getting this exception maybe you don't have the administration rights to your system so check with your admin and ask for the rights. If you do have administrator rights please open your IDE(e.g Visual Studio as an Administrator).You might also get this exception if you are trying to access the processes of 32 bit configuration system but your system has 64 bit configuration.
I am using .Net 4.5.2 and IIS 8.5.9
In IIS Manage->Pool Application->Advance Setting->Identity change
ApplicationPoolIdentity to Custom Account and set Administrator User

Installing msi with c# not working properly

I'm trying to install 3 msi drivers one after another.
There are all in the same folder and I'm using the same attrubutes for all of them/
I already did it before and it worked fine, but now I don't know what possibly can go wrong.
string attributesToDownload = "REINSTALL=ALL /qb- /norestart";
Process proc = Process.Start("msiexec.exe", string.Format("/i \"{0}\" {1}", driverPath, attributesToDownload));
proc.WaitForExit();
return proc.ExitCode;
The curious thing is:
For the first driver my ExitCode is 1603.
For the second sriver the ExitCode is 0 but the driver is not really installed.
For the third one it all works fine.
When I tried to install the first and the second drivers directly from cmd with the same attributes it installed succesfully.
"msiexec /i driverPath REINSTALL=ALL /qb- /norestart"
Waiting for some ideas.....
Got it, I think.... without the REINSTALL=ALL, the only way to do it (that I found) is uninstalling the current version and than installing the new one
If you're doing REINSTALL=ALL to get this to work, then you are updating an existing product installed on the system. That's ok, maybe you want to patch the existing product, but you don't seem to be aware that you cannot install the same product twice - the newer one needs to a patch or and update like your REINSTALL=ALL or a major upgrade. If you want to uninstall the older one then you need a major upgrade!!! There is no need to uninstall the older version because a major upgrade does that automatically.

Uninstalling a previous component before installing a new one using VS 2005 Setup Project

I have a Custom Action that should execute during the Install portion of an .msi setup. I have a previous version that was installed using InstallShield (which was overkill) and wanted to move to the simpler VS Setup Proj because I do not require all the control that an .isproj provides. However, doing a straight install with my new .msi seems to install side by side with the previous version. Here's what I have found out so far:
I have my product ID
I have written code that will uninstall the previous version through creating a process that uses MsiExec.exe (code will follow)
Tried implementing the custom action to uninstall during setup but it seems you can only have one instance of MsiExec.exe running at a time.
Have been to this post (http://stackoverflow.com/questions/197365/vs-setup-project-uninstall-other-component-on-install), which didnt help.
Custom Action code:
//Exe used to uninstall
string fileName = "MsiExec.exe";
//Product ID of versions installed using InstallShield
string productID = "{DC625BCF-5E7B-4FEF-96DD-3CDBA7FC02C1}";
//Use /x for uninstall and use /qn to supress interface
ProcessStartInfo startInfo = new ProcessStartInfo(fileName, string.Format("/x{0}", productID));
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.UseShellExecute = false;
//Start process
Process uninstallProcess = Process.Start(startInfo);
//Wait until uninstall is complete
uninstallProcess.WaitForExit();
My hope is to eventually deploy my .msi via ClickOnce, so I am hoping for an option that will fit into deployment option. Currently everything is written in .NET 2.0 and VS 2005, but I do have .NET 4.0 and VS 2010 available to me if there is a new option that works.
Any help is appreciated.
I was able to install over the top of the previous install by making the product code of my setup the same as the code of the older version. Didn't dawn on me to try that because when you create a new version of the setup package, VS always prompts you to change your product code.

Categories