I have built a custom regular expression class. I also have a database value that is a list of characters that I don't want to be allowed anywhere in my web application. My custom regular expression class will take all other regular expressions and ensure that my list of unwanted characters are not allowed. My custom regular expression class is register in my Global.asax.cs and since it is a value in the database it can be changed when deemed necessary. Now what I need to do is find a way to take the regex error message and add on to it with something like: "This field cannot contain the following: " + mybadcharacterlist;
Already tried this:
public const string AlphaErrMsg = "This field can only contain letters. This field cannot include the following characters: " + RestrictedCharacterList.GetList();
Which didn't work because the error parameter for RegularExpressionAttribute requires a const and calling my GetList method isn't a constant.
protected void Application_Start()
{
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof (RestrictCharRegExpressAttribute), typeof(RegulatExpressionAttributeAdapter);
}
public class RestrictCharRegExpressAttribute : RegularExpressionAttribute
{
public RestrictCharRegExpressAttribute(string propRegex) : base(GetRegex(propRegex)) {}
private static string GetRegex(string propRegex)
{
in indexPropRegex = propRegex.IndexOf('^');
string restrictedCharsAction = "(?!.*[" + RestrictedCharacterList.GetList() + "])";
propRegex = indexPropRegex == -1 ? propRegex.Insert(0, restrictedCharsAction) : propRegex.Insert(indexPropRegex + 1, restrictedCharsAction);
return propRegex;
}
}
public static class RestrictedCharacterList
{
public static string GetList()
{
string restrictedChars;
if (HttpContext.Current?.Session == null)
{
restrictedChars = EnvironmentSettingsDA.GetSetting(AppConfiguration.Settings.ConnectionString, "CAMPS", "RESTRICTED_CHARACTERS");
}
else
{
restrictedChars = HttpContext.Current.Session.GetDataFromSession<string>("RESTRICTED_CHARACTERS");
if (restrictedChars == null)
{
restrictedChars = EnvironmentSettingsDA.GetSetting(AppConfiguration.Settings.ConnectionString, "CAMPS", "RESTRICTED_CHARACTERS");
HttpContext.Current.Session.SetDataToSession<string>("Restricted_Characters", restrictedChars);
}
}
return restrictedChars;
}
}
public class User
{
public const string IsAlphaRegex = "^[a-zA-Z]*$'
public const string AlphaErrMsg = "This field can only contain letters.";
[RestrictCharRegExpress(IsAlphaRegex, ErrorMessage = AlphaErrMsg)]
public string FirstName { get; set; }
}
The expected results would be to add a message to all my regex error messages describing what characters are not allowed while ensuring that list of characters can be changed in the database.
The way you do this is to override FormatErrorMessage in RestrictCharRegExprAttribute:
public class RestrictCharRegExprAttribute: RegularExpressionAttribute
{
public RestrictCharRegExpressAttribute(string propRegex): base( GetRegex(propRegex)
{
this.Message = ...; // localized message
}
private string Message { get; }
public override string FormatErrorMessage(string propertyName)
{
return this.Message;
}
}
Special thanks to Reviews Alot for leading me down the right path but this is what I did to accomplish what I was trying to do.
Added the following to RestrictedCharacterList class:
public static class RestrictedCharacterList
{
public static string GetErrorMessage()
{
return " Valid values cannot include the following restricted characters: " + GetList();
}
}
Added the following to RestrictCharRegExpressAttribute class:
public class RestrictCharRegExpressAttribute : RegularExpressionAttribute
{
public string AddToRestrictCharErrorMessage { get; set; }
public override string FormatErrorMessage(string name)
{
if (string.isNullOrWhiteSpace(AddToRestrictedCharErrorMessage))
{
return base.FormatErrorMessage(name);
}
else
{
return AddToRestrctCharErrorMessage + " " + RestrictedCharacterList.GetErrorMessage():
}
}
}
And then when you want the special character message appended to an existing error message you assign the data attribute like so:
public class User
{
public const string IsAlphaRegex = "^[a-zA-Z]*$'
public const string AlphaErrMsg = "This field can only contain letters.";
[RestrictCharRegExpress(IsAlphaRegex, AddToRestrictCharErrorMessage = AlphaErrMsg)]
public string FirstName { get; set; }
}
Related
Based on https://gigi.nullneuron.net/gigilabs/data-driven-tests-with-nunit/ website. I have try to create a simple testcase which prepare for read data in the future. But I have no idea how to handle Argument and use it properly
I have try to set as a object, but i think this might not be a correct solution
[TestCaseSource("GetDataString")]
public void TestMethod2(object configs)
{
}
Here is source code
namespace SAP
{
[TestFixture]
public class Scenario1
{
// This one Give System.ArgumentException
[TestCaseSource("GetDataString")]
public void TestMethod(List<Config> configs)
{
Console.WriteLine("Config " + configs);
}
// This one can handle an Exception
[TestCaseSource("GetDataString")]
public void TestMethod2(object configs)
{
}
public static List<Config> GetDataString()
{
var datas = new List<Config>();
datas.Add(new Config("Nick", "Coldson"));
return datas;
}
}
public class Config
{
public string NickName { get; set; }
public string Name { get; set; }
public Config(string nickname, string name)
{
NickName = nickname;
Name = name;
}
}
}
Here is error msg
System.ArgumentException : Object of type 'SAP.Config' cannot be
converted to type 'System.Collections.Generic.List`1[SAP.Config]'.
The testcasesource has slightly different definition pattern. Assuming you use nunit 3 it should be:
[TestCaseSource(typeof(MyTestData), nameof(GetDataString))]
public void TestMethod2(List<Config> configs)
{
...
}
public class MyTestData
{
public static IEnumerable GetDataString()
{
var datas = new List<Config>();
datas.Add(new Config("Nick", "Coldson"));
return new TestCaseData(datas);
}
}
For more info, check the documentation:
https://github.com/nunit/docs/wiki/TestCaseData
Your GetDataString returns a List<Config>.
Meaning, your test method with a [TestCaseSource("GetDataString")] will be executed as many times as many items the list has and your method must match the item type.
//// This one throws System.ArgumentException
//[TestCaseSource("GetDataString")]
//public void TestMethod(List<Config> configs)
//{
// Console.WriteLine("Config " + configs);
//}
// This one is ok
[TestCaseSource("GetDataString")]
public void TestMethod(Config config)
{
Console.WriteLine(config);
}
If you need to get List<Config> instances in your test, then your source must return some collection containing list items.
This was from my university C# - windows forms exam, im trying to resolve some old subjects, but i seem to find myself stuck in this situation. This is my code:
abstract class CarFile
{
private string marca;
private readonly string serie;
public CarFile(string marca, string serie)
{
this.marca = marca;
this.serie = serie;
}
public string GetMarca
{
get { return this.marca; }
set { this.marca = value; }
}
public string GetSerie
{
get { return this.serie; }
}
public abstract string GetDescriere();
}
Then I have to do this:
my second class called ServiceFile : CarFile, ICloneable. in this class i have an array or list of strings called RepairComands which contains the necessary repairs.
- a private atribute called "motor" which can only take the following vallues {gas,gpl,hibrid} .
- a constructor which throws a generic exception if "serie==null"
-overrides the abrstract method getDescriere() to return the complete description of the car file
this is my code:
public class MyException : System.Exception
{
public MyException(string mesaj) : base(mesaj) { }
}
class ServiceFile : CarFile, ICloneable, IComparable, IReparabil
{
string[] RepairComands;
private enum motor { motorina, benzina, GPL, electric, hibrid };
public ServiceFile(string serie, string marca, string[] RepairComands):base(serie,marca){
if (serie == null)
{
throw new MyException("MESAJ");
}
this.RepairComands = RepairComands;
}
//not sure if this is correct
public override string GetDescriere()
{
string msj = string.Format("the car {0} with serial {1} and necess. repairs {2}", this.GetMarca, this.GetSerie, this.RepairComands);
return msj;
}
public object Clone()
{
ServiceFile clone = new ServiceFile(this.GetSerie, this.GetMarca, this.RepairComands);
return clone;
}
//implemented IComparable to be able to compare here 2 files by the number of repairs needed
public int CompareTo(object obj)
{
ServiceFile altafisa = (ServiceFile)obj;
if (this.RepairComands != altafisa.RepairComands)
return 1;
else return 0;
}
//overloads ToString to return the complete file description
public override string ToString()
{
return this.GetMarca + " "+ this.GetSerie + " " + this.RepairComands;
}
}
}
so far so good. this actually works.
but my problem comes now:
I have to define the interface IRep which contains 2 methods : void RepairCar() and void AddRepair(string repair).
THen ServiceFile class implements : IRep, and the function RepairCar() will be used for removing the last repair from the collection RepairComands
and the function AddRepair(string repair) will be used to add a repair in the collection RepairComands.
(For allowing the access to the private list of Repairs we should overload the index operator[] )
Thank you so much for your help, I'm a beginnes in C# and just wanted to understand better this subject that was given in my class so i could learn
Thank you
I have the following:
public class Mail {
public String Obfuscate(String email) {
return email.Replace("#", "at").Replace(".", "dot");
}
}
I am calling the method Obfuscate in a class, as follows:
public class Resolver {
public Data GetData () {
return new Data { Email = new Mail().Obfuscate(myEmail) };
}
public String Translate(string value) { /* Some Code */ }
}
The problem is that Obfuscate does the replacement in English: # > at, . > dot
But in the Resolver class the method Translate does exactly what I need ...
How can I "pass" the Translate method to the Obfuscate method so this one uses it to translate # and . to at and dot in the current language?
So the code line inside Obfuscate:
return email.Replace("#", "at").Replace(".", "dot");
Would be become:
return email.Replace("#", Translate("#")).Replace(".", Translate("."));
Where Translate would be the method that I am "passing" to it.
Than You,
Miguel
Consider a different design:
public interface ITranslator
{
string Translate(string s);
}
public class Obfuscator
{
public Obfuscator(ITranslator translator)
{
this.translator = translator;
}
public string Obfuscate(string email)
{
var at = translator.Translate("at");
var dot = translator.Translate("dot");
return email.Replace("#", at).Replace(".", dot);
}
private ITranslator translator;
}
public class EnglishTranslator : ITranslator
{
public string Translate(string s)
{
return s;
}
}
public class PolishTranslator : ITranslator
{
public PolishTranslator() //or `FileInfo dictionaryFile` parameter perhaps
{
// for simplicity
translations = new Dictionary<string, string>();
translations.Add("at", "malpa");
translations.Add("dot", "kropka");
}
public string Translate(string s)
{
return translations[s];
}
private Dictionary<string, string> translations;
}
However you really should consider using a ResourceManager. Resource related mechanisms are designed to deal with translations.
I think #BartoszKP's answer is the right design decision. For completeness, here's how to do what you asked.
Change Mail to take a Func<string,string>:
public class Mail {
public String Obfuscate(String email, Func<string,string> translate) {
return email.Replace("#", translate("at")).Replace(".", translate("dot"));
}
}
And pass your Translate method to it:
public class Resolver {
public Data GetData () {
return new Data { Email = new Mail().Obfuscate(myEmail, Translate) };
}
public String Translate(string value) { /* Some Code */ }
}
I am passing a custom variable type from one action to another action in a workflow. Here is the definition of the custom object
public class ConfigDatabase
{
public string Name;
public string Host;
public string Port;
public string Instance;
public string User;
public string Password;
}
public class ConfigDatabases
{
public string DatabaseToUse;
public List<ConfigDatabase> DatabaseList;
public ConfigDatabases()
{
DatabaseList = new List<ConfigDatabase>();
}
}
public class ConfigEnvironment
{
public ConfigDatabases EnvironmentConfigDatabase;
public ConfigEnvironment()
{
EnvironmentConfigDatabase = new ConfigDatabases();
}
public ConfigDatabase ReturnDatabaseInfo()
{
ConfigDatabase ConfigDatabaseInfo = new ConfigDatabase();
for (int Count1 = 0; Count1 < EnvironmentConfigDatabase.DatabaseList.Count; Count1++)
{
if (EnvironmentConfigDatabase.DatabaseList[Count1].Name == EnvironmentConfigDatabase.DatabaseToUse)
{
ConfigDatabaseInfo = EnvironmentConfigDatabase.DatabaseList[Count1];
return ConfigDatabaseInfo;
}
}
return ConfigDatabaseInfo;
}
public string GetDatabaseConnectionString()
{
ConfigDatabase DatabaseInfo = ReturnDatabaseInfo();
string ConnectionString = "Data Source=(description=(address=(protocol=tcp)(host=" + DatabaseInfo.Host + ")(port=" + DatabaseInfo.Port + "))(connect_data=(sid=" + DatabaseInfo.Instance + ")));User ID=" + DatabaseInfo.User + ";Password=" + DatabaseInfo.Password + ";";
return ConnectionString;
}
}
During the first step of the action, it will run the following code to load the config data from a file and store in an object (ConfigEnvironment) that is returned in function Execute
public sealed class InitializeEnvironment : CodeActivity<ConfigEnvironment>
{
// Define an activity input argument of type string
public InArgument<string> EnvironmentFileLocation { get; set; }
// If your activity returns a value, derive from CodeActivity<TResult>
// and return the value from the Execute method.
protected override ConfigEnvironment Execute(CodeActivityContext context)
{
// Obtain the runtime value of the Text input argument
string EnvironmentFile = context.GetValue(this.EnvironmentFileLocation);
EnvironmentConfigInitialization EnvironmentInitialize = new EnvironmentConfigInitialization(EnvironmentFile);
ConfigEnvironment EnvironmentDetail = EnvironmentInitialize.LoadData();
return EnvironmentDetail;
}
}
In the subsequent activity in the workflow, I would like to obtain the data stored in this object. However, the following code will have a compile error as EnvironmentDetail object could not find the function GetDatabaseConnectionString.
public sealed class ExecuteSQL : CodeActivity<DataRowCollection>
{
// Define an activity input argument of type string
public InArgument<string> SQLScript { get; set; }
public InArgument<ConfigEnvironment> EnvironmentDetail { get; set; }
// If your activity returns a value, derive from CodeActivity<TResult>
// and return the value from the Execute method.
protected override DataRowCollection Execute(CodeActivityContext context)
{
string connectionString4 = EnvironmentDetail.GetDatabaseConnectionString(); //This create a compile error
}
}
The compile warning is the following
'System.Activities.InArgument' does not contain a definition for 'GetDatabaseConnectionString' and no extension method 'GetDatabaseConnectionString' accepting a first argument of type 'System.Activities.InArgument' could be found (are you missing a using directive or an assembly reference?)
As it turns out, EnvironmentDetail is of Type InArgument (or InArgument<ConfigEnvironment>) but not of Type ConfigEnvironment You need to do a context.Get<ConfigEnvironment>() to get a variable of Type ConfigEnvironment.
Let me know if this solves your problem or if there's something else still amiss ;-)
I'm not sure of all of the correct terminology for what I am trying to do, so I will just dive in with some code.
Current Setup:
public enum NavigationLinks
{
[FriendlyName("System Dashboard")]
SystemDashboard,
[FriendlyName("Trading Dashboard")]
TradingDashboard,
}
public class UINameAttribute : Attribute
{
public string Value { get; private set; }
public UINameAttribute(string Value)
{
this.Value = Value;
}
}
What I would like:
public enum NavigationLinks
{
[FriendlyName]
SystemDashboard,
[FriendlyName]
TradingDashboard,
}
public class UINameAttribute : Attribute
{
public string Value { get; private set; }
public UINameAttribute(string Value)
{
this.Value = Value;
}
public UINameAttribute()
{
string AttributedValue = this.AttributedObject.ToString();
// Take the value of the attribute and add a space in between the camel case.
}
}
Can I access the underlying 'thing' that the attribute is on from within the constructor of the attribute?
No, you can't access attributed member from within the attribute's constructor.
But why do that anyway, if you already have a logic how to resolve friendly name from enum value.
public enum NavigationLinks
{
SystemDashboard,
TradingDashboard,
}
public static class Program
{
private static string ToFriendlyName(string defaultName)
{
var sb = new StringBuilder(defaultName);
for (int i = 1; i < sb.Length; ++i)
if (char.IsUpper(sb[i]))
{
sb.Insert(i, ' ');
++i;
}
return sb.ToString();
}
public static void Main(string[] args)
{
var value = NavigationLinks.SystemDashboard;
var friendlyName = ToFriendlyName(value.ToString());
}
}
In addition to Stipo's approach you can also write an extension method to get the name, something like this:
public static class NavigationLinksExtension
{
public static string GetFriendlyName(this NavigationLinks navLink)
{
string tmpName = navLink.ToString();
tmpName = Regex.Replace(tmpName, "(?<=[a-z])([A-Z])", " $1"); // insert space
return tmpName;
}
}
Then you can simply access the value:
NavigationLinks nl = NavigationLinks.TradingDashboard;
string nlFriendlyName = nl.GetFriendlyName();
An attribute can't (directly) get access to the thing it is describing. If you want ToString() to be the default and only override it occasionally, you would be better off with a helper function (e.g. GetFriendlyName) that defaults to ToString(), but replaces it with the value in a FriendlyName attribute should one exist.
Please try the following:
var inputString = NavigationLinks.SystemDashboard;
Regex.Replace(inputString, "([A-Z][a-z0-9]+)+", "$1$2");
Use the DescriptionAttribute (or create a custom attribute), then, using Reflection to get the value:
Create the class EnumDescriptions (using System.ComponentModel and System.Reflection):
public class EnumDescriptions
{
public static string StringValueOf(Enum value)
{
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
return attributes[0].Description;
}
And put Description in the Enum:
public enum Animals
{
[Description("System Dashboard")]
SystemDashboard,
[Description("Trading Dashboard")]
TradingDashboard,
}
To get the values:
static void Main(string[] args)
{
Console.WriteLine(EnumDescriptions.StringValueOf(Animals.SystemDashboard));
Console.WriteLine();
Console.WriteLine(EnumDescriptions.StringValueOf(Animals.TradingDashboard));
Console.Read();
}