Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 1 year ago.
Improve this question
I work at an application that receives data from user and I try to write a validator function for it, but I'm not sure if this is the correct way to proceed.
Example: The user will input a number (as string, don't ask why I don't use an int, let it be a string), let's say "103", and I'will use this number inside a function, but first, at the beginning of that function I call a validator function:
private bool ValidateCommandCode(string code)
{
bool isValid = false;
byte commandByte = new byte();
if (byte.TryParse(code, out commandByte))
{
isValid = true;
}
else
{
Log.Error($"Command number {CommandCode} for the request is not valid!");
isValid = false;
}
return isValid;
}
private async void MainFunction()
{
if (ValidateCommandCode(CommandCode) == false)
return;
// ... do the magic with the CommandCode ...
}
in the same manner, I want to validate another field filled by the user:
e.g of data: 000A000B
private bool ValidateRequestData(string data)
{
bool isValid = false;
if (!String.IsNullOrEmpty(Payload) && !String.IsNullOrWhiteSpace(Payload))
{
if (Payload.Trim().Replace(" ", "").Length % 2 != 0)
{
Log.Error($"Payload (Data) {Payload} for the request doesn't have an even number of bytes!");
isValid = false;
}
else
{
isValid = true;
}
}
else
{
isValid = true;
}
return isValid;
}
Is this a good way to proceed? Aren't so many flags "isValid" too confusing?
I would create a separate class for validation and decouple logging by passing a logger to the validator.
public interface ILogger
{
void Error(string message);
}
public class Logger : ILogger
{
public void Error(string message) { }
}
public class LoggingValidator
{
private readonly ILogger _logger;
// Payload looks like a hex number, so we check this.
private static readonly Regex _payloadExp = new Regex(#"^\s*([0-9A-F]{2} *)+\s*$", RegexOptions.Compiled);
public LoggingValidator(ILogger logger)
{
_logger = logger;
}
public bool CheckCommand(string value)
{
if (byte.TryParse(value, out _)) // Discard operator _
return true;
_logger.Error("Your message.");
return false;
}
public bool CheckPayload(string value)
{
if (_payloadExp.IsMatch(value ?? ""))
return true;
_logger.Error("Your message.");
return false;
}
}
public class Program
{
private static void Main(string[] args)
{
var validator = new LoggingValidator(new Logger());
string value = "123";
if (validator.CheckCommand(value)) { /* ... */ }
if (validator.CheckPayload(value)) { /* ... */ }
}
}
Related
Objects are rendered as strings, (name of the object), in Application Insights custom dimensions when passed as arguments to ilogger. The actual values are not shown.
Register Application Insights
services.AddApplicationInsightsTelemetry();
New log
public class HealthController : ControllerBase
{
private readonly ILogger<HealthController> _logger;
public HealthController(ILogger<HealthController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
var health = new HealthViewModel()
{
ok = false
};
_logger.LogInformation("Hlep me pls {health}", health);
return Ok(health);
}
}
Result
I do not want to this this for every log:
var health = new HealthViewModel()
{
ok = false
};
_logger.LogInformation("Hlep me pls {health}", JsonConvert.SerializeObject(health));
I tried creating a middleware for application insights but the value is still the name of the object..
Why are arguments not rendered as json?
Edit
It seems like
var health = new
{
ok = false
};
_logger.LogInformation("HEJ2 {health}", health);
works but not
var health = new HealthViewModel
{
ok = false
};
_logger.LogInformation("HEJ2 {health}", health);
Not supported
Quote from https://github.com/microsoft/ApplicationInsights-dotnet/issues/1722
I think you're expecting too much of the logger. It doesn't know about JSON format, it just calls Convert.ToString on properties
Convert.ToString typically calls ToString() and the default ToString implementation for new classes is simply to return the type name
What you can do
Use ToJson() on objects logged to ILogger and create a middleware for application insights and modify the name of the log and the custom dimensions.
Middleware
public class ProcessApiTraceFilter : ITelemetryProcessor
{
private ITelemetryProcessor Next { get; set; }
private readonly IIdentity _identity;
private readonly IHostEnvironment _hostEnvironment;
public ProcessApiTraceFilter(ITelemetryProcessor next, IHostEnvironment hostEnvironment, IIdentity identity)
{
Next = next;
_identity = identity;
_hostEnvironment = hostEnvironment;
}
public void Process(ITelemetry item)
{
item.Process(_hostEnvironment, _identity);
Next.Process(item);
}
}
Implementation
public static class ApplicationInsightsExtensions
{
public static void Process(this ITelemetry item, IHostEnvironment hostEnvironment, IIdentity identity)
{
if (item is TraceTelemetry)
{
var traceTelemetry = item as TraceTelemetry;
var originalMessage = traceTelemetry.Properties.FirstOrDefault(x => x.Key == "{OriginalFormat}");
if (!string.IsNullOrEmpty(originalMessage.Key))
{
var reg = new Regex("{([A-z]*)*}", RegexOptions.Compiled);
var match = reg.Matches(originalMessage.Value);
var formattedMessage = originalMessage.Value;
foreach (Match arg in match)
{
var parameterName = arg.Value.Replace("{", "").Replace("}", "");
var parameterValue = traceTelemetry.Properties.FirstOrDefault(x => x.Key == parameterName);
formattedMessage = formattedMessage.Replace(arg.Value, "");
}
traceTelemetry.Message = formattedMessage.Trim();
}
if (identity != null)
{
var isAuthenticated = identity.IsAuthenticated();
const string customerKey = "customer";
if (isAuthenticated && !traceTelemetry.Properties.ContainsKey(customerKey))
{
var customer = identity.Customer();
if (customer != null)
{
traceTelemetry.Properties.Add(customerKey, customer.ToJson());
}
}
var request = identity.Request();
const string requestKey = "request";
if (request != null && !traceTelemetry.Properties.ContainsKey(requestKey))
{
traceTelemetry.Properties.Add(requestKey, request.ToJson());
}
}
var applicationNameKey = "applicationName";
if (hostEnvironment != null && !string.IsNullOrEmpty(hostEnvironment.ApplicationName) && !traceTelemetry.Properties.ContainsKey(applicationNameKey))
{
traceTelemetry.Properties.Add(applicationNameKey, hostEnvironment.ApplicationName);
}
}
}
}
Register application insights and middleware in startup
services.AddApplicationInsightsTelemetry();
services.AddApplicationInsightsTelemetryProcessor<ProcessApiTraceFilter>();
ToJson
public static class ObjectExtensions
{
private static readonly string Null = "null";
private static readonly string Exception = "Could not serialize object to json";
public static string ToJson(this object value, Formatting formatting = Formatting.None)
{
if (value == null) return Null;
try
{
string json = JsonConvert.SerializeObject(value, formatting);
return json;
}
catch (Exception ex)
{
return $"{Exception} - {ex?.Message}";
}
}
}
Log
//Log object? _smtpAppSettings.ToJson()
_logger.LogInformation("Email sent {to} {from} {subject}", to, _smtpAppSettings.From, subject)
Result
from your custom dimensions i can see that it`s not considering the health obj param as an extra data
_logger.LogInformation("Hlep me pls {health}", health);
trying using the jsonConverter within the string itself.
_logger.LogInformation($"Hlep me pls {JsonConvert.SerializeObject(health)}");
I would like to code a framework in C# Console Application(CLI), details aren't important.
I don't know, how to recognize commands cleanly, and shortly.
I tried with switch-case:
public static void command_recognizing(string command) // random example
{
string[] tmp_array = command.Split(' ');
switch(tmp_array[0])
{
case("help"):
method_library.help(); // no need argument
break;
case("time"):
method_library.time(); // no need argument
break;
case("shutdown"):
method_library.shutdown(tmp_array); // need argument
break;
default:
Console.WriteLine("Error! {0} is not a known command!",tmp_array[0]);
break;
}
}
I also tried if-else:
public static void command_recognizing(string command) // random example
{
string[] tmp_array = command.Split(' ');
if(command.Contains("help"))
{
method_library.help(); // no need argument
}
else if(command.Contains("time"))
{
method_library.time(); // no need argument
}
else if(command.Contains("shutdown"))
{
method_library.shutdown(tmp_array); // need argument
}
else
{
Console.WriteLine("Error! {0} is not a known command!",tmp_array[0]);
}
}
I tried to store the commands in a string array, still the same, long and ugly.
There is any other way, to make the command recognizing shorter, cleaner and easier to modify?
Foregive me for my english. Feel free to correct me!
You could use Reflection to execute methods of a class.
void Main() {
var cmd = new Commands();
while (!cmd.Exitting) {
var cmdline = Console.ReadLine();
var cmdargs = Regex.Split(cmdline.Trim(), #"\s+");
if (!cmd.TryInvokeMember(cmdargs[0], cmdargs.Skip(1).ToArray()))
Console.WriteLine($"Unknown command: {cmdargs[0]}");
}
}
// Define other methods and classes here
public class Commands {
public bool Exitting { get; private set; }
public Commands() {
Exitting = false;
}
public void exit() {
Exitting = true;
}
public int sum(object[] args) {
return args.Select(s => Convert.ToInt32(s)).Sum();
}
public bool TryInvokeMember(string methodName, object[] args) {
var method = typeof(Commands).GetMethod(methodName.ToLower());
if (method != null) {
object res;
if (method.GetParameters().Length > 0)
res = method.Invoke(this, new object[] { args });
else
res = method.Invoke(this, new object[0]);
if (method.ReturnType != typeof(void))
Console.WriteLine(res.ToString());
return true;
}
else
return false;
}
}
I have the following code in my class:
private static void SetUserMeta(string pUserToken, string pMetaKey, string pMetaValue, Action<bool> callback)
{
BuddyClient client = CreateBuddy();
bool rValue = false;
client.LoginAsync((user, state) =>
{
if (state.Exception != null)
{
rValue = false;
}
else
{
client.Metadata.SetAsync((result, resultState) =>
{
if (resultState.Exception != null)
{
rValue = false;
}
else
{
rValue = true;
}
}, key: pMetaKey, value: pMetaValue);
}
callback(rValue);
}, token: pUserToken);
}
and I want to get rValue and return it from my other method which is the following
public static void SetBuddyData(string pUserToken, BuddyData pMetaValue, Action<bool> callback)
{
//my problem is here and I don't know how to get and return data from SetUserMeta
return SetUserMeta(pUserToken, "SavedGameData", pMetaValue.Serialize());
}
And also I want to call this return value from my application. These codes are in my library. How can I do it?
Just pass callback to SetUserMeta like
public static void SetBuddyData(string pUserToken, BuddyData pMetaValue, Action<bool> callback)
{
SetUserMeta(pUserToken, "SavedGameData", callback);
}
And call SetBuddyData like this
SetBuddyData("my user token", myBundle, isLoggedIn => HandleUserLogin(isLoggedIn));
Where at HandleUserLogin you will process bool callback data, returned at callback(rValue); in SetUserMeta method. It's body example is shown
next
public static void HandleUserLogin(bool isLogged)
{
Console.WriteLine("user is {0} logged in", isLogged ? "" : "not");
}
You also can take advantage of method group syntax and call SetBuddyData method like:
SetBuddyData("my user token", myBundle, HandleUserLogin);
have a php code like this,going to convert it in to C#.
function isValid($n){
if (preg_match("/\d+/",$n) > 0 && $n<1000) {
return true;
}
return false;
}
Here is my try,BUT error shown Error is "expected class, delegate, enum, interface or struct error C#"
public string IsValidate(string Item)
{
string Result = Item;
try
{
Result = System.Text.RegularExpressions.Regex.Replace(InputTxt, #"(\\)([\000\010\011\012\015\032\042\047\134\140])", "$2");
}
catch(Exception ex)
{
console.WriteLine(ex.Message)
}
return Result;
}
What is the error,Is there any other way to implement this better than my try ?
i got this snippet from here code
You haven't define this method inside a class/struct that is why you are getting this error. You may define this method inside a class.
public class MyValidator
{
public string IsValidate(string Item)
{
//Your code here
}
}
Later you can use it like:
MyValidator validator = new MyValidator();
validator.IsValid("Your string");
Also you are missing semicolon at the end of the Console.Write statement, plus 'c' for Console should be in uppercase
Edit:
Since in your php code, it looks like you are trying to see if the string passed is an integer and it is less than 1000, you may use the int.TryParse like the following:
public class MyValidator
{
public bool IsValidate(string Item)
{
string Result = Item;
int val;
if (int.TryParse(Item, out val) && val > 0 && val < 1000)
{
return true;
}
else
{
return false;
}
}
}
In you main method you can do:
static void Main()
{
MyValidator validator = new MyValidator();
Console.WriteLine(validator.IsValidate("asdf123")); // This will print false
Console.WriteLine(validator.IsValidate("999")); //This will print true
Console.WriteLine(validator.IsValidate("1001")); //This will print false
}
In C# a method must be placed inside a class or struct:
public class Validator {
public string IsValidate(string item) {
...
}
}
In this case I would probably translate it like this:
public static class Validator {
public static bool IsValid(string item) {
int value;
return int.TryParse(item, out value)
&& value > 0 && value < 1000;
}
}
You could define your function inside a static class such that you dont have to create an instance of it before invoking the function. Like,
public static class Validator
{
public static string IsValidate(string item)
{
// ...
}
}
Then, you can call it using:
Validator.IsValidate("String to validate")
EDIT: You could then check that your function is returning what you expect by doing:
if(Validator.IsValidate("String to validate") == "Expected result")
{
/* Logic to be executed here */
}
What do I have to do to say that InvokeMethod can invoke a method and when using special options like Repeat it shall exexute after the Repeat.
My problem for now is that the method will already exexute before it knows that it has to be called 100 times.
class Program
{
static void Main()
{
const bool shouldRun = true;
new MethodExecuter()
.ForAllInvocationsUseCondition(!Context.WannaShutDown)
.InvokeMethod(A.Process).Repeat(100)
.When(shouldRun).ThenInvokeMethod(B.Process).Repeat(10)
.ForAllInvocationsUseCondition(Context.WannaShutDown)
.When(shouldRun).ThenInvokeMethod(C.Process);
}
}
MethodExpression
public class MethodExpression
{
private bool _isTrue = true;
private readonly MethodExecuter _methodExecuter;
public MethodExpression(bool isTrue, MethodExecuter methodExecuter)
{
_isTrue = isTrue;
_methodExecuter = methodExecuter;
}
public MethodExecuter ThenInvokeMethod(Action action)
{
if (_isTrue)
{
action.Invoke();
_isTrue = false;
}
return _methodExecuter;
}
}
MethodExecuter
public class MethodExecuter
{
private bool _condition;
private int _repeat = 1;
public MethodExpression When(bool isTrue)
{
return new MethodExpression(isTrue && _condition, this);
}
public MethodExecuter InvokeMethod(Action action)
{
if (_condition)
{
for (int i = 1; i <= _repeat; i++)
{
action.Invoke();
}
}
return this;
}
public MethodExecuter ForAllInvocationsUseCondition(bool condition)
{
_condition = condition;
return this;
}
public MethodExecuter Repeat(int repeat)
{
_repeat = repeat;
return this;
}
}
Use a final method ("go", or "execute") to actually kick things off.
new MethodExecuter()
.ForAllInvocationsUseCondition(!Context.WannaShutDown)
.InvokeMethod(A.Process).Repeat(100)
.When(shouldRun).ThenInvokeMethod(B.Process).Repeat(10)
.ForAllInvocationsUseCondition(Context.WannaShutDown)
.When(shouldRun).ThenInvokeMethod(C.Process)
.Go();
What you've provided looks a bit like programming a workflow or state machine. In order to capture invocations and respect conditions during execution, you'd need to change your approach slightly.
Instead of invoking actions as they come in, consider pushing your actions into a queue and then providing an mechanism to run the state machine.
new MethodInvoker()
.ForAllInvocationsUseCondition(true)
.InvokeMethod( Process.A ).Repeat(100)
.Run();
There are a lot of ways to skin this cat, but I think one source of this difficulty is in the fact that you actually invoke the method within the InvokeMethod() method (go figure!).
Typically, we use fluent APIs to turn syntax that is evaluated from the inside-out into something that can be expressed in a left-to-right fashion. Thus, the expression builder components of the interface are used to build up state throughout the expression, and only at the end does the "real work" happen.
One solution to your immediate problem is to queue up each action with its associated options (invocation conditions, repeat count, etc.), and add some ExecuteAll() method to MethodExecuter that dequeues and executes the fully configured actions at the end of the member chain.
Another solution would be to put all of the execution options inside the InvokeMethod() method; something like:
.Invoke(x => x.Method(A.Process).Repeat(100))
This method would look something like:
public MethodExecuter Invoke(Action<IExecutionBuilder> executionBuilder)
{
var builder = new ExecutionBuilder();
executionBuilder(builder);
var action = builder.Action;
var repeat = builder.RepeatCount;
if (_condition)
{
for (int i = 1; i <= repeat; i++)
{
action();
}
}
return this;
}
I haven't worked through this in Visual Studio, but the other items would be something like:
public interface IExecutionBuilder
{
IExecutionBuilder Method(Action action);
IExecutionBuilder Repeat(int count);
}
public class ExecutionBuilder : IExecutionBuilder
{
public ExecutionBuilder()
{
RepeatCount = 1; // default to repeat once
Action = () => {}; // default to do nothing, but not null
}
public IExecutionBuilder Method(Action action)
{
Action = action;
return this;
}
public IExecutionBuilder Repeat(int repeat)
{
RepeatCount = repeat;
return this;
}
public int RepeatCount { get; private set; }
public Action Action { get; private set; }
}
Note that RepeatCount and Action are not exposed on the interface. This way, you will not see these members when calling .Invoke(x => x., but will have access to them when using the concrete ExecutionBuilder class inside the Invoke() method.
You could have a SetInvokeMethod and an Execute Method.
SetInvokeMethod(Action).Repeat(100).Execute()
In a sentence, your code is too "eager". The InvokeMethod method is called, and performs the action, before your fluent grammar structure tells your code how many times it should repeat.
To change this, try also specifying the method you are invoking as a private field in your methodInvoker, then include a command that is a "trigger" to actually perform the commands. The key is "lazy evaluation"; in a fluent interface, nothing should be done until it has to; that way you have most of the control over when it does happen.
public class FluentMethodInvoker
{
Predicate condition = ()=>true;
Predicate allCondition = null;
Action method = ()=> {return;};
bool iterations = 1;
FluentMethodInvoker previous = null;
public FluentMethodInvoker(){}
private FluentMethodInvoker(FluentMethodInvoker prevNode)
{ previous = prevNode; }
public FluentMethodInvoker InvokeMethod(Action action)
{
method = action;
}
//Changed "When" to "If"; the function does not wait for the condition to be true
public FluentMethodInvoker If(Predicate pred)
{
condition = pred;
return this;
}
public FluentMethodInvoker ForAllIf(Predicate pred)
{
allCondition = pred;
return this;
}
private bool CheckAllIf()
{
return allCondition == null
? previous == null
? true
: previous.CheckAllIf();
: allCondition;
}
public FluentMethodInvoker Repeat(int repetitions)
{
iterations = repetitions;
return this;
}
//Merging MethodExecuter and MethodExpression, by chaining instances of FluentMethodInvoker
public FluentMethodInvoker Then()
{
return new FluentMethodInvoker(this);
}
//Here's your trigger
public void Run()
{
//goes backward through the chain to the starting node
if(previous != null) previous.Run();
if(condition && CheckAllIf())
for(var i=0; i<repetitions; i++)
method();
return;
}
}
//usage
class Program
{
static void Main()
{
const bool shouldRun = true;
var invokerChain = new FluentMethodInvoker()
.ForAllIf(!Context.WannaShutDown)
.InvokeMethod(A.Process).Repeat(100)
.When(shouldRun)
.Then().InvokeMethod(B.Process).Repeat(10)
.ForAllIf(Context.WannaShutDown)
.When(shouldRun)
.Then().InvokeMethod(C.Process);
//to illustrate that the chain doesn't have to execute immediately when being built
invokerChain.Run();
}
}