InstallerSetup.cs pass installation parameters in from1.cs - c#

I have properly overwrite commit in InstallerSetup.cs I do not wish to write the user entered value to app.config but rather I want to pass the string Context.Parameters["TESTPARAMETER"]; to another class in form1.cs on load function. I tried string test = InstallerSetup.Context.Parameters["TESTPARAMETER"];
but getting InstallerSetup.Context is null. Please Help.
InstallerSetup.cs
public static string SQLSERVERNAME = "";
public static string HMSTENANTDB;
public static string SQLLOGIN;
public static string SQLPASSWORD;
public override void Commit(IDictionary savedState)
{
base.Commit(savedState);
try
{
SQLSERVERNAME = Context.Parameters["SQLSERVERNAME"];
HMSTENANTDB = Context.Parameters["HMSTENANTDB"];
SQLLOGIN = Context.Parameters["SQLLOGIN"];
SQLPASSWORD = Context.Parameters["SQLPASSWORD"];
}
catch (Exception e)
{
MessageBox.Show("Failed to update the application configuration file : " + e.Message);
base.Rollback(savedState);
}
}
from1.cs
InstallerSetup InsSetup = new InstallerSetup();
string Vsqlserver = InsSetup.Installers.Count.ToString();
string Vtenant = "";
if (InsSetup.Context != null)
{
Vtenant = InsSetup.Context.Parameters["HMSTENANTDB"];
}
else
{
Vtenant = "context is null";
}

As far as I can tell, the issue is that the property values are not being passed into the custom action. That would be the most obvious explanation. A commentfrom the poster says:
"passed those parameters to the custom action...................................... SQLSERVERNAME = Context.Parameters["SQLSERVERNAME"];
etc...
//................there is only these 4 lines in my custom actions"
which is essentially repeating the code that was previously posted.
This is NOT passing the values into the custom action. This is retrieving values which must already have been passed into the custom action.
Assuming that the custom action has been correctly added to (typically) the install nod of the custom action, and also assuming that the property names are in a TextBoxes dialog in the install, the values must be passed in to the custom action via the CustomActionData settings. To use one example, the CustomActionData setting must be something like:
/SQLSERVERNAME=[SQLSERVERNAME]
or /SQLSERVERNAME=[EDITA1] if EDIOTA1 is being used because that's the default property name.
However there is no reference to the TextBoxes (or any other) install dialog in the original question, so it's not really clear where the value of (say) SQLSERVERNAME is supposed to come from. It may be passed in on the msiexec command line, for example.

Related

Logging reserved words/characters

I have a *.resx string that looks like this:
Failed to deserialize an object of type '{0}' from the following string:{1}{2}
This string is being used to log such kinds of errors and currently, the logging statement looks like this:
_logger.LogError(Resources.FailedToDeserialize, typeof(MyType).Name, Environment.NewLine, invalidJsonString);
As you can see - I need to pass Environment.NewLine each time to display my logs correctly for any OS.
I am curious are there any reserved string interpolation words/characters to insert such values?
For example, my string could look like this:
Failed to deserialize an object of type '{0}' from the following string:{NewLine}{2}
And my logging statement would be a bit simpler:
_logger.LogError(Resources.FailedToDeserialize, typeof(MyType).Name, invalidJsonString);
One thing you can do is some form of pre processing on application start up by reading the resource file, replacing your keyword of choice i.e {NewLine} with Environment.NewLine and then use that cached string for the entirety of your application life time.
You can make the fields readonly and do some reflection magic to set the value but this example should give you an idea of how to solve your current problem.
public static class LoggingMessageTemplates
{
//Reference your resource here e.g Resource.FailedToDeserialize
public static string FailedToDeserialize = "Resource.Something {NewLine} Something Else";
public static void FormatMessages()
{
var stringFields = typeof(LoggingMessageTemplates)
.GetFields()
.Where(x => x.FieldType == typeof(string));
foreach(var field in stringFields)
{
if (field.GetValue(null) is not string fieldValue)
{
throw new InvalidCastException($"Failed to cast field {field.Name} to string.");
}
field.SetValue(null, fieldValue.Replace("{NewLine}", Environment.NewLine));
}
}
}
//On application startup, format the resources to use the Environment.NewLine char of the current system.
LoggingMessageTemplates.FormatMessages();
//When logging, reference the LoggingMessageTemplates class rather than the direct resource.
Console.WriteLine(LoggingMessageTemplates.FailedToDeserialize);
//i.e
_logger.LogError(LoggingMessageTemplates.FailedToDeserialize, typeof(MyType).Name, invalidJsonString);

How can I pick up a stacktrace for a Step in the AfterStep binding in SpecFlow

I'm running a Unit test using SpecFlow in VS2013
I have a method called AfterStep which looks like this:
[AfterStep]
private static void AfterStep()
{
string attribute = ScenarioContext.Current.CurrentScenarioBlock.ToString();
string extractedValue = GetAttributeValue(attribute);
}
Here is the code for the GetAttributeValue method:
public static string GetAttributeValue(string attribute)
{
string attrValue = "";
StackTrace stackTrace = new StackTrace();
MethodBase method = stackTrace.GetFrame(1).GetMethod();
switch (attribute)
{
case "Given":
GivenAttribute givenAttr = (GivenAttribute)method.GetCustomAttributes(typeof(GivenAttribute), true)[0];
attrValue = givenAttr.Regex;
break;
case "When":
WhenAttribute whenAttr = (WhenAttribute)method.GetCustomAttributes(typeof(WhenAttribute), true)[0];
attrValue = whenAttr.Regex;
break;
case "Then":
ThenAttribute thenAttr = (ThenAttribute)method.GetCustomAttributes(typeof(ThenAttribute), true)[0];
attrValue = thenAttr.Regex;
break;
}
return attrValue;
}
But it doesnt seem to return the method that was called before the "AfterStep", ie " Step_ConnectToVMS".
Here is the example of the Step_ConnectToVMS step method:
[When(#"I open VMS and connect")]
public static void Step_ConnectToVMS(Table LoginDetails)
{
//Log into VMS
}
Ive noticed that it works if I call "GetAttributeValue" from within the Step_ConnectToVMS method itself. It just doesnt work if I call it in the "AfterStep" method.
What I essentially want the "AfterStep" method to grab is the the StackFrame for the method that's called before it (in this instance Step_ConnectToVMS) so that I can extract the attribute value.
With these values I can then use them in my custom results logger, which contains extra information (which i'm not at liberty to go into here) but what I really need are these step "descriptions" ie the attribute (Given, When Then) and the value ("I open VMS and connect") to form the headers for this log.
What I do when I get these values is I write them to an XML log, this log then gets picked up by an ASP.NET webserver and generates the page.
As I mentioned in the comments I have a system that works but it involved me putting "GetAttributeValue" in every step method I create. Where as I want it to sit in the "AfterStep" method so that its just in 1 place.

How can i use response.redirect from inside a function defined in Class file in c# 3.0

I have a simple function GetPageName(String PageFileName, String LangCode) defined inside a class file. I call this function from default.aspx.cs file, In this function I am not able to use Response.Redirect("Error.aspx") to show user that error has been generated.
Below is example of Code
public static string GetPageName(String PageFileName, String LangCode)
{
String sLangCode = Request("Language");
String pgName = null;
if ( sLangCode.Length > 6)
{
Reponse.Redirect("Error.aspx?msg=Invalid Input");
}
else
{
try
{
String strSql = "SELECT* FROM Table";
Dataset ds = Dataprovider.Connect_SQL(strSql);
}
catch( Exception ex)
{
response.redirect("Error.aspx?msg="+ex.Message);
}
}
return pgName;
}
I have may function defined in Business and Datalayer where i want to trap the error and redirect user to the Error page.
HttpContext.Current.Response.Redirect("error.aspx");
to use it your assembly should reference System.Web.
For a start, in one place you're trying to use:
response.redirect(...);
which wouldn't work anyway - C# is case-sensitive.
But the bigger problem is that normally Response.Redirect uses the Page.Response property to get at the relevant HttpResponse. That isn't available when you're not in a page, of course.
Options:
Use HttpContext.Current.Response to get at the response for the current response for the executing thread
Pass it into the method as a parameter:
// Note: parameter names changed to follow .NET conventions
public static string GetPageName(String pageFileName, String langCode,
HttpResponse response)
{
...
response.Redirect(...);
}
(EDIT: As noted in comments, you also have a SQL Injection vulnerability. Please use parameterized SQL. Likewise showing exception messages directly to users can be a security vulnerability in itself...)

C# String Property and string literal concatenation issue

I am a bit new at C# and I have run into a string concatenation issue. I am hoping someone might be able to give me a hint and help me resolve this. I have searched Google extensively and have spent more than a week on this so any help/advice would be greatly appreciated.
I have created a custom PathEditor for a string property. The property basically allows the user to key in a file to use in the app. If the file typed in is correct, it shows in the property cell as it should. What I am trying to do is output to the property cell an error message if the file typed in does not exist - I check this in my file validator. Here is the string literal issue.
If I use:
return inputFile+"Error_";
this works OK and I get the outpur file123.txtError_ in the property grid cell.
If I use:
return "Error_"+inputFile;
I get only the inputFile without the literal "Error_". Sot he property grid cell shows file123.txt in the property grid cell.
I have checked and inputFile is a string type. Any ideas as to why this is happening?
Also, is there any way to change to font, and/or, color of the message output? I tried to change the background of the property grid cell and I understand that this is not possible to do.
Thank you.
Z
More of the code:
[
Description("Enter or select the wave file. If no extension, or a non .wav extension, is specified, the default extension .wav will be added to the filename."),
GridCategory("Sound"),
Gui.Design.DisplayName ("Input Sound"),
PathEditor.OfdParamsAttribute("Wave files (*.wav)|*.wav", "Select Audio File"),
Editor(typeof(PathEditor), typeof(System.Drawing.Design.UITypeEditor))
]
public string InputWavefile
{
get { return System.IO.Path.GetFileName(inputtWavefile); }
set
{
if (value != inputWavefile) // inputWavefile has been changed
{
// validate the input stringg
_inputWavefile = FileValidation.ValidateFile(value);
// assign validated value
inputWavefile = _inputWavefile;
}
}
}
My guess is that you've got a funky character at the start of inputFile which is confusing things - try looking at it in the debugger using inputFile.ToCharArray() to get an array of characters.
The string concatenation itself should be fine - it's how the value is being interpreted which is the problem, I suspect...
I'm guessing your filename looks something like this, C:\Folder\FileName.txt when you start out.
In your FileValidation.ValidateFile() method you
return "Error_" + InputFileName;
it now looks like this: Error_C:\Folder\FileName.txt.
So, when you run the line below,
get { return System.IO.Path.GetFileName( _inputWavefile ); }
it strips off the path and returns the filename only, FileName.txt.
Even when the filename is not valid, you are still running System.IO.Path.GetFileName() on it.
Assuming this is a PropertyGrid in winforms app. Then it's neither a string concatenation issue, nor PropertyGrid issue, as could be proven by the following snippet. So you need to look elsewhere in your code:
public partial class Form1 : Form {
PropertyGrid pg;
public Form1() {
pg = new PropertyGrid();
pg.Dock = DockStyle.Fill;
this.Controls.Add(pg);
var inputFile = "some fileName.txt";
var obj = new Obj();
obj.One = "Error_" + inputFile;
obj.Two = inputFile + "Error_";
pg.SelectedObject = obj;
}
}
class Obj {
public string One { get; set; }
public string Two { get; set; }
}

Custom workflow activity errors 'Value cannot be null'

I'm creating a custom workflow activity in VS2010 targeting .NET 3.5. The DLL is actually being used in a Microsoft System Center Service Manager custom workflow, but I don't think that is my issue.
I have a public string property, that the user types in the string of what the activity should use. However, when the WF runs, it errors out 'value cannot be null'. I want to target if it is my code or something else.
When we drag my custom activity onto the designer, I'm able to type in the text of the string on the designer for that property.
public static DependencyProperty ChangeRequestStageProperty = DependencyProperty.Register("ChangeRequestStage", typeof(String), typeof(UpdateChangeRequestStage));
[DescriptionAttribute("The value to set the ChangeRequestStage Property in the ChangeRequest Extension class.")]
[CategoryAttribute("Change Request Extension")]
[BrowsableAttribute(true)]
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
public String Stage
{
get { return ((String)(base.GetValue(UpdateChangeRequestStage.ChangeRequestStageProperty))); }
set { base.SetValue(UpdateChangeRequestStage.ChangeRequestStageProperty, value); }
}
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
EnterpriseManagementGroup emg = CreateEMG();
//System.WorkItem.ChangeRequest Extension - ClassExtension_928bec0a_cac4_4a0a_bd89_7146c9052fbe
ManagementPackClass mpcChangeRequest = emg.EntityTypes.GetClass(new Guid("8c6c6057-56ad-3862-47ec-dc0dde80a071"));
//System.WorkItemContainsActivity Relationship Class
ManagementPackRelationship workItemContainsActivityRelationship = emg.EntityTypes.GetRelationshipClass(new Guid("2DA498BE-0485-B2B2-D520-6EBD1698E61B"));
EnterpriseManagementObject changeRequest = null;
//Loop thru each emo (Change Request in this case), and assign it. There will never be more than 1 emo returned
foreach (EnterpriseManagementObject obj in emg.EntityObjects.GetRelatedObjects<EnterpriseManagementObject>(executionContext.ContextGuid, workItemContainsActivityRelationship, TraversalDepth.OneLevel, ObjectQueryOptions.Default))
{ changeRequest = obj; }
EnterpriseManagementObjectProjection emop = new EnterpriseManagementObjectProjection(changeRequest);
if (emop != null)
{ emop.Object[mpcChangeRequest, "ChangeRequestStage"].Value = Stage; }
emop.Commit();
return base.Execute(executionContext);
}
Since it is getting a 'value cannot be null' error, I'm guessing it's on this line:
emop.Object[mpcChangeRequest, "ChangeRequestStage"].Value = Stage;
I'm going to test and see if hardcoding a value works or not. Any ideas?
enter code here
try this
if (emop != null && emop.Object[mpcChangeRequest, "ChangeRequestStage"] != null)
emop.Object[mpcChangeRequest, "ChangeRequestStage"].Value = Stage
I didn't want to leave this question wide open, so I'm updating it as to how I resolved this (a long time ago).
Rather than working with an EnterpriseManagementObjectProjection (emop), I worked with a standard EnterpriseManagementObject (emo). From there, I was able to follow a similar format from above:
ManagementPackClass mpcChangeRequest = emg.EntityTypes.GetClass(new Guid("8c246fc5-4e5e-0605-dc23-91f7a362615b"));
changeRequest[mpcChangeRequest, "ChangeRequestStage"].Value = this.Stage;
changeRequest.Commit();

Categories

Resources