How to use a Variable Name which was Obtained at Run-Time - c#

All, to provide a on-the-fly mechanism for debugging an application in different languages I am using the required resource string (in a foreign language) to display the English equivalent at run-time should the user require it. This is done using
public static string GetMessage(string messageKey)
{
CultureInfo culture = Thread.CurrentThread.CurrentCulture;
if (!culture.DisplayName.Contains("English"))
{
string fileName = "MessageStrings.resx";
string appDir = Path.GetDirectoryName(Application.ExecutablePath);
fileName = Path.Combine(appDir, fileName);
if (File.Exists(fileName))
{
// Get the English error message.
using (ResXResourceReader resxReader = new ResXResourceReader(fileName))
{
foreach (DictionaryEntry e in resxReader)
if (e.Key.ToString().CompareNoCase(messageKey) == 0)
return e.Value.ToString();
}
}
}
return null;
}
Where GetName is defined as
public static string GetName<T>(Expression<Func<T>> expression)
{
return ((MemberExpression)expression.Body).Member.Name;
}
I usually display localised messages in my application like
Utils.ErrMsg(MessageStrings.SomeMessage);
or
Utils.ErrMsg(String.Format(MessageStrings.SomeMessage, param1, param2));
Now I can display the relevent English message from my app running in a different culture using
Utils.ErrMsg(Utils.GetMessage(
Utils.GetName(() => MessageStrings.ErrCellAllocStatZeroTotal)) ??
MessageStrings.ErrCellAllocStatZeroTotal);
I want to avoid having to use a lambda expression in the call to GetName and the use of null from GetMessage and using ??, how can I achieve this [if at all possible]?
Thanks for your time.

I do not fully understand your code, but if you just want to access the properties of an object dynamically, try this (you have to replace [Object] and "PropertyName" with your specific values):
// get the property from object
PropertyInfo Property = [Object].GetType().GetProperty("PropertyName");
// get the value
int value = (int)Property.GetValue([Object], null);

Related

Why does t.GetProperty always return null?

I'm coding an app using Visual Studio and Xamarin in C#, and I'd like the user to be able to take a photo and save it in his phone to later be retrieved within the app. To do this, I need to start by saving the photo in the phone. My photos are of type FileResult and I put all the photos in a list and save the list thanks to this block of code:
public static List<FileResult> SavedListPhoto
{
get
{
var savedList = Deserialize<List<FileResult>>(Preferences.Get(nameof(SavedListPhoto), null));
Console.WriteLine(savedList);
return savedList ?? new List<FileResult>();
}
set
{
var serializedList = Serialize(value);
Preferences.Set(nameof(SavedListPhoto), serializedList);
Console.WriteLine(nameof(SavedListPhoto));
}
}
static T Deserialize<T>(string serializedObject) => JsonConvert.DeserializeObject<T>(serializedObject);
static string Serialize<T>(T objectToSerialize) => JsonConvert.SerializeObject(objectToSerialize);
Now that the list is saved in the phone, I'd like to be able to access the list and the elements inside it, as well as modify it. I'm using this block of code to accomplish it:
private List<FileResult> GetList(object instance, string path)
{
var pp = path.Split('/');
Type t = instance.GetType();
foreach( var prop in pp)
{
Console.WriteLine(prop);
PropertyInfo propInfo = t.GetProperty(prop);
Console.WriteLine(propInfo);
if (propInfo != null)
{
instance = propInfo.GetValue(instance, null);
t = instance.GetType();
}
else throw new ArgumentException("Properties path is not correct");
}
return (List<FileResult>)instance;
}
However, whatever I do, the ArgumentException gets thrown. Obviously, it's because propInfo is always null, but I don't understand why. The instance I'm giving is the list itself, and the path I'm giving is the following:
/data/user/0/com.companyname.app1/cache/2203693cc04e0be7f4f024d5f9499e13/9fe8dae02ada45a5bb9eba67d39f7d06/8907af5726ff404fadb415261a7dc71e.jpg, which is the path that I get from the following block of code (after being modified so I get only the path above):
Preferences.Get("SavedListPhoto", "false")
I've looked but I found no problems which related exactly to what I have. If someone could help me it would be greatly appreciated :)

CS1061 'IEnumerable<<anonymous type: x>>' does not contain a definition for dump

I just want to get the password out of my software KeePass.
After using the code from an old question here Link to the question, im getting this error message:
S1061 'IEnumerable<<anonymous type: string Group, string Title, string Username, string Password>>' does not contain a definition for 'Dump' and no accessible extension method 'Dump' accepting a first argument of type 'IEnumerable<<anonymous type: string Group, string Title, string Username, string Password>>' could be found (are you missing a using directive or an assembly reference?) KeePasso C:\Users\prusinma\source\repos\KeePasso\KeePasso\Program.cs 36 Active
This is the code im using:
using System.Linq;
using KeePassLib;
using KeePassLib.Keys;
using KeePassLib.Serialization;
namespace KeePasso
{
class Program
{
static void Main()
{
var dbpath = #"\\xxx\Home_VIE\xxx\Desktop\KeePassDatabase\Database.kdbx";
var keypath = #"\\xxx\Home_VIE\xxx\Desktop\KeePassDatabase\Database.key";
var masterpw = "1234abcd";
var ioConnInfo = new IOConnectionInfo { Path = dbpath };
var compKey = new CompositeKey();
compKey.AddUserKey(new KcpPassword(masterpw));
compKey.AddUserKey(new KcpKeyFile(IOConnectionInfo.FromPath(keypath))); // Keyfile
var db = new PwDatabase();
db.Open(ioConnInfo, compKey, null);
var kpdata = from entry in db.RootGroup.GetEntries(true)
select new
{
Group = entry.ParentGroup.Name,
Title = entry.Strings.ReadSafe("Title"),
Username = entry.Strings.ReadSafe("UserName"),
Password = entry.Strings.ReadSafe("Password"),
};
kpdata.Dump(); // this is how Linqpad outputs stuff
db.Close();
}
}
}
In the last rows in the code, there is a red underline at Dump. Which displays the same error message i shared above.
I was already trying to find similiar questions and in most of them they were related to the type. But as i can see, all the datas/entries in Title, Username and Password are strings.
Would appreciate if someone could help me here out. Id also be open for a other solution how to read out the password from the database.
Thanks!
Since kpdata is collection of anonimous types, which has overriden ToString (and if entry.Strings.ReadSafe returns string or some type with "correctly" overriden ToString method) you can just use Console.WriteLine on it:
Console.WriteLine(string.Join(Environment.NewLine, kpdata));; // instead of kpdata.Dump();
Otherwise you will need to find a way to import LINQPad's Dump method into your project or just use some json serialization library to convert object to string.
Cast it to object!
//But This works!
((object)d).Dump();
// as does this)
(d as Object).Dump()

Exception has been thrown by the target of an invocation ERROR when trying to changind AD user with ASP.net C#

I've tryed a lot of others solutions, and I still didn't make it work. Can someone help me please.
my code is like that:
I saw something about secureString, I tryed to use it but it still didn't work.
I saw too another solution that says to use var rather than string in the variables. Didn't work
I dont know if I'm doing something wrong or if those solutions that dosoen't work.
public bool RedefinirSenha(string pUsuario, string pSenhaAtual, string pNovaSenha)
{
var NovaSenha = pNovaSenha;
var SenhaAtual = pSenhaAtual;
var Usuario = pUsuario;
//string Pwd = String.Format(#"""{0}""", NovaSenha);
//byte[] pwdCerto = System.Text.Encoding.Unicode.GetBytes(Pwd);
try
{
string LDAP = myLDAPpath;
DirectoryEntry ADcon = new DirectoryEntry(LDAP, Usuario, SenhaAtual, AuthenticationTypes.Secure);
if (ADcon != null)
{
DirectorySearcher search = new DirectorySearcher(ADcon);
search.Filter = "(SAMAccountName=" + Usuario + ")";
SearchResult result = search.FindOne();
if (result != null)
{
DirectoryEntry userEntry = result.GetDirectoryEntry();
if (userEntry != null)
{
try
{
userEntry.Invoke("ChangePassword", new object[] { SenhaAtual, NovaSenha }, AuthenticationTypes.Secure);
userEntry.Properties["LockOutTime"].Value = 0;
userEntry.CommitChanges();
userEntry.Close();
return true;
}
catch (Exception INex)
{
this.Erro = INex.Message + "COD:\r\n" + INex.InnerException;
userEntry.Close();
return false;
}
}
}
}
return true;
}
catch (Exception ex)
{
this.Erro = ex.Message;
return false;
}
}
First, there will be no difference at runtime if you declare the variables as var or string. Using the var keyword lets the compiler decide what the type is. Because you're assigning a string to it, then it is a string too. In most cases, var is fine. There are only very rare cases when you need to explicitly specify the type.
Second, DirectoryEntry.Invoke is defined like this:
public object Invoke (string methodName, params object[] args);
That may seem like you need to pass an object array, but that is not the case. The params keyword is a way to allow you to pass multiple parameters that get used inside the method as an array. So when you call it like this:
userEntry.Invoke("ChangePassword", new object[] { SenhaAtual, NovaSenha }, AuthenticationTypes.Secure);
The first parameter is an object array and the second parameter is AuthenticationTypes.Secure, then both of those get put inside the args array for use inside the Invoke method. But that is not what ChangePassword looks for. If this doesn't make sense to you, read the documentation for the params keyword and it should help.
When you call .Invoke("ChangePassword", ...), it calls the native Windows IADsUser.ChangePassword method. That takes two parameters: a string with the old password and a string with the new password - not an object array and an AuthenticationTypes value. So you should be calling it like this:
userEntry.Invoke("ChangePassword", SenhaAtual, NovaSenha);
You don't need to worry about the authentication because the password can only be changed over a secure connection. In the documentation, it says it behaves the same way as (IADsUser.SetPassword](https://learn.microsoft.com/en-ca/windows/win32/api/iads/nf-iads-iadsuser-setpassword), where it attempts several different ways to achieve a secure connection for you.
There is another way to change the password if the DirectoryEntry connection is already over a secure connection. A secure connection can either be using Kerberos, which can be done using AuthenticationTypes.Sealing (this is best if you are on the same network as the domain controller):
var ADcon = new DirectoryEntry(LDAP, Usuario, SenhaAtual, AuthenticationTypes.Secure | AuthenticationTypes.Sealing);
Or if by using LDAPS (LDAP over SSL), which you can use just by specifying port 636 in the LDAP path (this is the only way if you are not on the same network as the domain controller):
var ADcon = new DirectoryEntry("LDAP://example.com:636", Usuario, SenhaAtual);
If you do that, then you can change the password by updating the unicodePwd attribute directly, in the very specific way it wants it (enclosed in quotes and encoded in UTF-16), like this:
userEntry.Properties["unicodePwd"].Remove(Encoding.Unicode.GetBytes($"\"{SenhaAtual}\""));
userEntry.Properties["unicodePwd"].Add(Encoding.Unicode.GetBytes($"\"{NovaSenha}\""));
This should perform slightly faster since all of the work (changing the password and setting lockOutTime) is done over one network request instead of two.

How to check if Parse(args) is true or false

I have code that is not throwing any error. I have used NDesk option set and added 2 string Parameters. I can see it has pulled correct names in args. But when I uses parse(args) it is not throwing an error. So I am assuming it is working.
I am trying to check if p(args) is true or false. But I can not use bool expressions to List<string>.
Any help how I can accomplish that. I want execute function if parse has correct arguments.
My code is like this
private static Regex fileNamePattern = new Regex(#"^[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}[.]pdf$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
//missing method name
{
string inputFile;
string outputFile;
var p = new OptionSet() {
{"i"," pdf file",v=>inputFile=v},{"o","index file with kws",v=>outputFile=v},
};
Console.WriteLine($"args length: {args.Length}");
Console.WriteLine($"args 0: {args[0]}");
Console.WriteLine($"args 1: {args[1]}");
p.Parse(args); //I would like to use this if(parse(args))
{
}
//
}
private static void UpdateImportIndexFile(string inputFile, string outputFile)
{
using (var dip = File.CreateText(outputFile))
{
var match = fileNamePattern.Match(Path.GetFileName(MainFilePath));
if (match.Success)
{
//create text file (outputfile);
}
}
}
Since p is an instance of a class and the parse method does not support a return to emulate in a sense the functionality of a TryParse wrap your parse in a try block
try{
val = p.Parse(args);
}catch(OptionException e){
//if false
}
For more information http://www.ndesk.org/doc/ndesk-options/NDesk.Options/OptionSet.html#M:NDesk.Options.OptionSet.Parse(System.Collections.Generic.IEnumerable{System.String})

How to change SSIS variable values in C#

I'm trying to set variables in code on an SSIS package I'm kicking off from C#.
Package pkg = app.LoadPackage(ConfigurationManager.AppSettings["SsisPkg"].ToString(), null);
pkg.Variables["User::FolderPath"].Value = Path.GetDirectoryName(e.FullPath);
pkg.Variables["User::FileName"].Value = Path.GetFileNameWithoutExtension(e.FullPath);
While debugging, I inspect the values directly after setting them, but nothing has changed. I can drill into the value (hover, navigate to it, edit value) so it doesn't seem to be that they aren't editable.
Any ideas what I'm doing wrong here?
Update: Thanks to billinkc, I'm comfortable what I'm doing should work so long as possibly other conditions are met. I've found that direct assignments in code fail (no error, just don't "take") and I cannot edit the values in the watch window. I can edit values when I'm inspecting them.
Could the actual issue be that there's a setting flagging these as read-only?
Answer Found: Needed to make the variables writable before setting the value:
pkg.Variables["User::FileName"].EvaluateAsExpression = false;
You're doing it right. I created a basic SSIS package. Has one Variable, FolderPath, type string. There is a single script task that fires an Information event and the contents of that expose the value of the FolderPath variable
I then created a basic C# console app like this
public class InformationListener : DefaultEvents
{
public override void OnInformation(DtsObject source, int informationCode, string subComponent, string description, string helpFile, int helpContext, string idofInterfaceWithError, ref bool fireAgain)
{
//base.OnInformation(source, informationCode, subComponent, description, helpFile, helpContext, idofInterfaceWithError, ref fireAgain);
Console.WriteLine(string.Format("{0} {1}", subComponent, description));
}
}
class Program
{
static void Main(string[] args)
{
string sourcePackage = string.Empty;
string path = string.Empty;
string variableName = string.Empty;
string designValue = string.Empty;
string newValue = string.Empty;
InformationListener listener = null;
sourcePackage = #"J:\Src\SO\SSIS\Package.dtsx";
path = #"J:\runtime";
variableName = "User::FolderPath";
listener = new InformationListener();
Application app = new Application();
Package pkg = null;
Variable ssisVariable = null;
pkg = app.LoadPackage(sourcePackage, null);
ssisVariable = pkg.Variables[variableName];
designValue = ssisVariable.Value.ToString();
Console.WriteLine(string.Format("Designtime value = {0}", designValue));
ssisVariable.Value = path;
newValue = ssisVariable.Value.ToString();
Console.WriteLine(string.Format("new value = {0}", newValue));
DTSExecResult results = DTSExecResult.Canceled;
results = pkg.Execute(null, null, listener, null, null);
Console.WriteLine("Press any key to continue");
Console.ReadKey();
}
}
As you can tell from the variable inspection
and from my print statements
the design-time value of C:\designTime goes to J: because I forgot to escape my string above but we can pretend it shows J:\runtime.
All this said, unless we serialize the package with a call to the SaveToXml method, the value of User::FolderPath resets to the design time value once the object goes out of scope. Permanently updating would look like
app.SaveToXml(sourcePackage, pkg, null);
OP EDIT this discussion and examples led me to the answer:
http://social.msdn.microsoft.com/Forums/sqlserver/en-US/dad8e218-1fe0-49db-89da-5715fb6d4b21/sql-2008-r2-ssis-c-script-task-not-setting-variable

Categories