Where does OnAfterInstall event go? - c#

I've had serious problems on how to solve this: I don't know where the OnAfterInstall event goes.
Let me explain myself. I created a C# project which compiles perfectly and built in Release mode. After that, I've created a Setup Project using the wizard. I have added an extra dialog, which lets the user choose between two languages. Now, my problem is that I want to store that language into the registry (or app.config file, the easier the better), and I've read that you need to detect it within the OnAfterInstall method in an inherited class of Installer.
Now, where should I put that class? Logic tells me it goes in the C# project, but it complains that neither Context nor Installer class exist. When I add this class to the Setup Project, it doesn't complain, but it doesn't work after that. Here's the class.
using System;
using System.Configuration.Install;
public class Install : Installer
{
public Install()
{
}
protected override void OnAfterInstall(IDictionary savedState)
{
string lang = Context.Parameters["lang"];
RegistryKey key = Registry.LocalMachine;
using (key = key.CreateSubKey(#"SOFTWARE\MyCompany\MyApp"))
{
key.SetValue("lang", lang);
key.Close();
}
base.OnAfterInstall(savedState);
}
}
PS: I'm already passing lang as CustomActionData using /lang=[LANG] (where LANG is the radio value)

First, you should add the RunInstallerAttribute to you class.
[RunInstaller(true)]
public class Install : Installer
...
Next, put the installer in a separate project (class library), e.g. MyCustomInstaller.
Finally, add the primary output of this project to a custom action in the custom actions editor of the setup project.
It's up to you in which custom action you want to use.

Related

How do I use the AppGlideModule in Xamarin.Android?

Using the Glide library on Xamarin.Android, I was hoping someone could shed some light on how to use the AppGlideModule. According to the documentation, I need to register my custom ModelLoader using the AppGlideModule.
Here is a link to the example in the Glide documentation:
http://bumptech.github.io/glide/tut/custom-modelloader.html#writing-the-modelloader
Here is my custom AppGlideModule class:
public class MyCustomGlideModule : AppGlideModule
{
public override void ApplyOptions(Context context, GlideBuilder builder)
{
base.ApplyOptions(context, builder);
}
public override void RegisterComponents(Context context, Glide glide, Registry registry)
{
registry.Prepend(
Java.Lang.Class.FromType(typeof(Java.IO.OutputStream)),
Java.Lang.Class.FromType(typeof(Drawable)),
new MyCustomImageStreamModelLoaderFactory()
);
}
}
I don't know if it's necessary, but if you'd like to see the classes I made for the ModelLoader, please let me know in the comments.
Old question but here is the trick. You will need to create an Android/Java library that contains an AppGlideModule wrapper. This library contains nothing else and is simply used to generate the GlideApp class. It needs to contain a static instance of your final AppGlideModule. Basically, it will look like this :
#GlideModule
public class XamarinGlideModule extends AppGlideModule {
public static AppGlideModule InjectedModule;
#Override
public void registerComponents(Context context, Glide glide, Registry registry) {
if(InjectedModule != null) {
InjectedModule.registerComponents(context, glide, registry);
}
}
}
You will then need to wrap this library in an Android binding library. Nothing is worthy of mention in this step, simply drop your built AAR in the binding project, add the matching version of the Glide Nuget and build.
You can then add a reference to that binding library in your app project. In your Android Application class, you will need to setup the InjectedModule static property to inject your Xamarin implementation. You must do this before any call to Glide, something similar to this :
public override void OnCreate()
{
base.OnCreate();
XamarinGlideModule.InjectedModule = new MyLoaderModule();
var temp = GlideApp.Get(this); // Init Glide, it will register your Xamarin module
}
Now there's one more option to use custom glide module from C# code. Just install package of this project:
https://github.com/KDD-Digital-Healthcare-GmbH/Kdd.Glide.AppModuleInjector
NOTE: if you need custom AppModule for glide just to accept self-signed certificates, you can install this package as well, it already has implementation of such module:
https://github.com/KDD-Digital-Healthcare-GmbH/Kdd.Glide.UnsafeUrlLoadingAppGlideModule

Resource files (resx) does not respect Custom Tool Namespace

In the resx properties, I changed the Custom Tool Namespace from DefaultNamespace to MyNamespace.Language and the following code is generated:
namespace MyNamespace.Language
{
public class CommentResources
{
public static global::System.Resources.ResourceManager ResourceManager {
get {
//removed code...
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DefaultNamespace.CommentResources", typeof(CommentResources).Assembly);
}
}
As you can see, only the class namespace is changed, but not the namespace passed in the ResourceManager constructor and because of that, when I instanciate ResourceManager(typeof(CommentResources)) and try to access a key, it throws MissingManifestResourceException, for example:
var manager = new ResourceManager(typeof(CommentResources));
var resource = manager.GetString("myKey");
How can I truly changed the namespace?
EDIT:
Take a look at my solution below. Whenever I create a resx file within Enviroment folder, it creates a unwanted namespace. That's what's I'm trying to avoid
I recently stumbled to the same issue.
It seems that Visual Studio 2017 generates code that creates ResourceManager from RootNamespace.SubFolder.ResourcesFileName instead of CustomToolNamespace.ResourcesFileName.
Since the code is created from the Visual Studio's Single-File Generator tool called either ResXFileCodeGenerator (for internal class) or PublicResXFileCodeGenerator (for public class) that internally uses StronglyTypedResourceBuilder class, there is no way to customize its behavior, other than implementing your own Single-File Generator as a Visual Studio extension and using it as a Generator for the EmbeddedResource.
Fortunately, there is a simpler workaround. In .csproj file, under EmbeddedResource tag, specify LogicalName tag with text value of RootNamespace.SubFolder.ResourcesFileName.resources.
In your specific case, it would look like this:
<LogicalName>DefaultNamespace.CommentResources.resources</LogicalName>

Winform app: Compiled App.Config-like file?

I would like to know if there is some kind of built-in compiled "App.Config" file?
The goal is to be able to have one of our library which can have some of its default values overriden when being used in some client application.
Thoses DLL are loaded dynamically, so I cannot just give a parameter in the constructor.
I don't want to use the App.config file because the user can edit those values(otherwise it would have been just fine).
There are several different ways to solve this.
If you like the idea of config-files, but do not want to have it accessible by end users in the compiled application, perhaps you can create your own settings-file in a format that suits your needs, and include it as an embedded resource?
An upside of this would be that you can access it as a regular XML or config file or whatever in Visual Studio, while it will be hidden from the end user. Personally I think I would prefer this to using special code / classes to store config-data.
To include a file as an embedded resource, include it into one of your Visual Studio projects, right click the included file and select Properties. Now under Build Action, select Embedded Resource. When you build your project now, the file will be included internally in the produced .dll-file.
I'm sure you'll be able to find lot's of info about how to access an embedded resource from code. As an example, there are some useful examples in this SO question. Note especially this answer, which also mentions an alternative way to include a resource.
Expanding on my comment... you could just make an interface for a settings class with hardcoded values, and then make different implementations of that interface. To actually change which one to use, all you'd need to do is comment/uncomment the line that instantiates an object into your settings variable before you build the dll:
public class MainDllProject
{
ISettings m_Settings;
public MainDllProject()
{
// Change this before compiling
this.m_Settings = new DebugSettings();
//this.m_Settings = new DeploySettings();
// use settings from the settings class
String setting1 = this.m_Settings.Setting1
Int32 setting2 = this.m_Settings.Setting2
//...
}
}
public interface ISettings
{
String Setting1 { get; }
Int32 Setting2 { get; }
}
public class DebugSettings: ISettings
{
public String Setting1
{ get { return "data_debug";} }
public Int32 Setting2
{ get { return 2;} }
}
public class DeploySettings: ISettings
{
public String Setting1
{ get { return "data_deploy";} }
public Int32 Setting2
{ get { return 1;} }
}
On finding "a built-in way of solving this", as you said, maybe this will be useful for you...
You can actually use the Visual Studio build configuration manager to build with different settings. Using the #If directives, you can automatically make it select which lines of code to use based on the configuration. A simple example based on the default debug configuration, which adds the "DEBUG=True" variable automatically:
public MainDllProject()
{
#If DEBUG Then
this.m_Settings = new DebugSettings();
#ElseIf
this.m_Settings = new DeploySettings();
#End if
}
You can actually make your own custom-named variables to check on just like that DEBUG one: after making a configuration, open the Project properties window, go to the Compile tab, select that specific configuration in the dropdown, and then at the bottom select "Advanced Compile Options". In there is a line "Custom constants" in which you can add such variables. For simple if-statements, you can just make a boolean like "CLIENTDEPLOY=True", and then you can use #If CLIENTDEPLOY Then in your code.

How to use class from other files in C# with visual studio?

I am a newbie of C# and MS visual studio, and I want to use the C# class which defined in another file, but can't get it work.
Here is the program.cs(and why can't I rename that file ?)
using System;
namespace TestCSharp2
{
class Program
{
static void Main(string[] args)
{
Class2 class2 = new Class2();
// here the IDE will complain that cant find namespace or balabala..
class2.setValue(10);
Console.WriteLine(class2.getValue().ToString());
Console.ReadKey();
}
}
}
And here is the Class2 that I want to use in file Class2.cs:
namespace TestCSharp2
{
class Class2
{
int i;
public void setValue(int i)
{
this.i = i;
}
public int getValue()
{
return this.i;
}
}
}
Should I #include or something? isn't use namespace enough?
As some guys asked if they are in the same assembly/same project, I presume they were, because here is the procedure how they are created:
A new project using the template of Console C# Project, then the program.cs was created by default.
The Class2.cs was created with [File] -> [New] -> [File] -> [C# class] and saved in the same folder where program.cs lives.
To be honest, I don't know if they are in same assembly / same project, but I guess they were.
According to your explanation you haven't included your Class2.cs in your project. You have just created the required Class file but haven't included that in the project.
The Class2.cs was created with [File] -> [New] -> [File] -> [C# class] and saved in the same folder where program.cs lives.
Do the following to overcome this,
Simply Right click on your project then -> [Add] - > [Existing Item...] : Select Class2.cs and press OK
Problem should be solved now.
Furthermore, when adding new classes use this procedure,
Right click on project -> [Add] -> Select Required Item (ex - A class, Form etc.)
Yeah, I just made the same 'noob' error and found this thread.
I had in fact added the class to the solution and not to the project.
So it looked like this:
Just adding this in the hope to be of help to someone.
It would be more beneficial for us if we could see the actual project structure, as the classes alone do not say that much.
Assuming that both .cs files are in the same project (if they are in different projects inside the same solution, you'd have to add a reference to the project containing Class2.cs), you can click on the Class2 occurrence in your code that is underlined in red and press CTRL + . (period) or click on the blue bar that should be there. The first option appearing will then add the appropriate using statement automatically. If there is no such menu, it may indicate that there is something wrong with the project structure or a reference missing.
You could try making Class2 public, but it sounds like this can't be a problem here, since by default what you did is internal class Class2 and thus Class2 should be accessible if both are living in the same project/assembly. If you are referencing a different assembly or project wherein Class2 is contained, you have to make it public in order to access it, as internal classes can't be accessed from outside their assembly.
As for renaming: You can click Program.cs in the Solution Explorer and press F2 to rename it. It will then open up a dialog window asking you if the class Program itself and all references thereof should be renamed as well, which is usually what you want. Or you could just rename the class Program in the declaration and again open up the menu with the small blue bar (or, again, CTRL+.) and do the same, but it won't automatically rename the actual file accordingly.
Edit after your question edit: I have never used this option you used, but from quick checking I think that it's really not inside the same project then. Do the following when adding new classes to a project: In the Solution Explorer, right click the project you created and select [Add] -> [Class] or [Add] -> [New Item...] and then select 'Class'. This will automatically make the new class part of the project and thus the assembly (the assembly is basically the 'end product' after building the project). For me, there is also the shortcut Alt+Shift+C working to create a new class.
namespace TestCSharp2
{
**public** class Class2
{
int i;
public void setValue(int i)
{
this.i = i;
}
public int getValue()
{
return this.i;
}
}
}
Add the 'Public' declaration before 'class Class2'.
According to your example here it seems that they both reside in the same namespace. I conclude that they are both part of the same project (if you haven't created another project with the same namespace)
and all classes by default are defined as internal to the project they are defined in, if haven't declared otherwise, therefore I guess the problem is that your file is not included in your project.
You can include it by right clicking the file in the solution explorer window => Include in project, if you cannot see the file inside the project files in the solution explorer then click the show the upper menu button of the solution explorer called show all files (just hover your mouse cursor over the button there and you'll see the names of the buttons).
Just for basic knowledge:
If the file resides in a different project\ assembly then it has to be defined,
otherwise it has to be defined at least as internal or public.
In case your class is inheriting from that class that it can be protected as well.
I was having the same problem here. Found out that the problem was with an Advanced Property of the file. There is there an option with the name 'Compilation Action' (may be not with the exact words, I am translating - my VS is in Portuguese).
My Class1.cs file was there as "Content" and I just had to change it to "Compile" to make it work, and have the classes recognized by the others files in the same project.
Just make two projects in two different files then rename the "Program.cs" of one of the two files
and copy it then paste it next to the Program.cs of the other file and that's it.
In your project there will be a file with .csproj extension.
Double click on it to open the project in the Visual Studio. Otherwise, if you make a new class, it won't link with other classes.
When u diclare your , var
you , can use private , declarasion
using System;
private Class class;

Editing a custom configuration section in an installer class

I am trying to update a custom configuration section of a web.config file during the installation of my product in a custom action. I wanted to use the actual configration classes to do this however when the installer runs it loads my installer class but then the
Configuration.GetSection throw a File Not Found exception as it is trying to load my custom section class from the windows system directory. I managed to get this to work by copying the required assemblies into the windows system directory but this is not an ideal solution as I cannot guarantee I will always have access to that directory.
How else can I solve this problem?
My update code looks like this
[RunInstaller(true)]
public partial class ProjectInstaller : Installer
{
public override void Install(System.Collections.IDictionary stateSaver)
{
//some code here
webConfig = WebConfigurationManager.OpenWebConfiguration("MyService");
MyCustomSection mySection = webconfig.GetSection("MyCustomSection") //<--File Not Found: CustomConfigSections.dll
//Update config section and save config
}
}
My config file looks like this
<configuration>
<configSections>
<section name="myCustomSection" type="CustomConfigSections.MyCustomSection, CustomConfigSections" />
</configSections>
<myCustomSection>
<!-- some config here -->
</myCustomSection>
</configuration>
Hope you would understand the answer the way it is intended.
Assuming that you have setup the installer to have your project output. If Not
Right Click on installer Project click add->Project Output->select your project
and then you can continue using your code.
Moreover if you are using dll except the .net Ones make sure to change there
properties to copylocal = true
If You want to read the element Before Installation use BeforeInstall Event
Handler and try reading your file. ihope your problem will be solved
If in case You want to read the element after installation Right Click On
installer project Click view->customActions->On Install Click Add Custom Action
->Select Application Folder -> Select Primary output from your project and click
ok .
Now Click on primary output and press F4 and in Custom Action Data write
/DIR="[TARGETDIR]\"
and after that write your code as follows.
[RunInstaller(true)]
public class ProjectInstaller : Installer
{
public ProjectInstaller()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
this.AfterInstall += new InstallEventHandler(ProjectInstaller_AfterInstall);
}
void ProjectInstaller_AfterInstall(object sender, InstallEventArgs e)
{
string path = this.Context.Parameters["DIR"] + "YourFileName.config";
// make sure you replace your filename with the filename you actually
// want to read
// Then You can read your config using XML to Linq Or you can use
// WebConfigurationManager whilst omitting the .config from the path
}

Categories

Resources