S1449 for String.Compare with StringComparison flag - c#

I have the following code:
string.Compare(value, expression.MatchValue, StringComparison.Ordinal) > 0;
This line creates the following SonarLint warning:
S1449: Define the locale to be used in this String operation.
I would assume that, because I specified the StringComparsion.Ordinal value, I did specify which local to use, and the S1449 warning should not be raised.
Is this correct? If so, is there any way to create bugs for SonarLint (I created an account at https://jira.sonarsource.com/browse/SLVS/ but it appears I do not have the privileges to create an account).
Thanks!

This issue has been recently fixed in SonarLint: https://jira.sonarsource.com/browse/SLVS-782
It will be part of the next release (version 1.8.0) due today or in the upcoming days.

Related

Message template should be compile time constant

I have this code
[HttpGet("average/{videoGuid}")]
public async Task<IActionResult> AverageRatingOfVideo([FromRoute] string videoGuid)
{
_logger.LogInformation($"Finding average rating of video : {videoGuid}");
var avg = await _ratingService.GetVideoRatingAverageAsync(videoGuid);
return Ok(avg);
}
and I'm getting a warning here $"Finding average rating of video : {videoGuid}"
Message template should be compile time constant
I'm using Rider, there is no suggestion to fix this warning.
I can't understand why this gives me a warning, how could I fix this ?
The way to get rid of the warning is to supply the variable videoGuid separately, like this:
_logger.LogInformation("Finding average rating of video : {VideoGuid}", videoGuid);
Here, I first removed the $ sign, thereby turning off the string interpolation performed by C#. The {videoGuid} in the string now becomes a "property" instead, and so I pass the variable as a second argument to LogInformation. Rider also complains that properties in strings should start with a capital letter, so I changed it to {VideoGuid}.
Now for the real question: Why is there a warning?
The answer is that string interpolation prevents structured logging. When you pass the variables after the message, you make it possible for the logger to save them separately. If you just save the log to a file you may not see a difference, but if you later decide to log to a database or in some JSON format, you can just change your logging sink and you will be able to search through the logs much easier without changing all the log statements in your code.
There's a good discussion of this over on Software Engineering Stack Exchange.
This is a false positive in the Serilog extension for Rider but other way to remove this warning is to disable the warning once (or globally in your class file).
// ReSharper disable once TemplateIsNotCompileTimeConstantProblem
_logger.LogInformation(messageTemplate);
Not the best solution but it's an option too.
Now, check Rof's answer about Why the warning.

MQL_DLLS_ALLOWED cannot be set

I want to know if there is any way to set the property id values of the ENUM_MQL_INFO_INTEGER using external program or dll or anything.
I tried this:
int OnInit()
{
//---
MQL_DLLS_ALLOWED = 1;
Print(MQLInfoInteger(MQL_DLLS_ALLOWED));
//---
return(INIT_SUCCEEDED);
}
It gave error:
'MQL_DLLS_ALLOWED' - l-value required TestingEnum.mq5 15 4
'1' - cannot convert enum TestingEnum.mq5 15 22
'=' - l-value required TestingEnum.mq5 15 21
Kindly, let me know what I can do.
I cannot help you with your question directly, mainly because of the reasons discussed in the comments. I believe you can check the value whether DLL is allowed, but you cannot enable/disable it easily. Maybe there is a way with running MT terminal from the command line, with some keys allowing or blocking dll, so you may check. But that means restarting your platform, I am not sure that is convenient.
If I were you, and tired of enabling/disabling dll dozen times, I would introduce a global variable of client terminal, with values 0 or 1 (doubles of course). Then, if it is zero, dlls are not called, and ea does not start (if you check that in OnInit()), if it is non-zero value, dll works. A simple script changing this GV can be written and hot keys assigned. In that case, hotkey blocks everything, and allows dll again when needed.
In case you need any help with that - I will edit my code and provide some basic examples.

C# won't compile a long const string with a \0 near the beginning

I've run into a peculiar case where I get the following error when creating certain types of string:
Unexpected error writing debug information -- 'Error HRESULT E_FAIL has been returned from a call to a COM component.'
This error is not new to Stack Overflow (see this question and this question), but the problems presented have nothing to do with this one.
For me, this is happening when I create a const string of a certain length that includes a null-terminating character (\0) somewhere near the beginning.
To reproduce, first generate a string of appropriate length, e.g. using:
var s = new string('a', 3000);
Grab the resulting string at runtime (e.g. Immediate Window or by hovering over the variable and copying its value). Then, make a const out of it:
const string history = "aaaaaa...aaaaa";
Finally, put a \0 in there somewhere:
const string history = "aaaaaaaaaaaa\0aa...aaaaa";
Some things I noticed:
if you put the \0 near the end, the error doesn't happen.
Reproduced using .NET Framework 4.6.1 and 4.5
Doesn't happen if the string is short.
Edit: even more precious info available in the comments below.
Any idea why this is happening? Is it some kind of bug?
Edit: Bug filed, including info from comments. Thanks everybody.
I'll noodle about this issue a little bit. This issue occurs both in VS2015 and earlier versions. So nothing directly to do with the C# compiler itself, this goes wrong in the ISymUnmanagedWriter2::DefineConstant2() implementation method. ISymUnmanagedWriter2 is a COM interface, part of the .NET infrastructure that all compilers use. And used both by Roslyn and the legacy C# compiler.
The comments in the Roslyn source code (actually dates back to the CCI project) that uses the method are illuminating enough, that there is trouble with this method was discovered before:
// EDMAURER If defining a string constant and it is too long (length limit is undocumented), this method throws
// an ArgumentException.
// (see EMITTER::EmitDebugLocalConst)
try
{
this.symWriter.DefineConstant2(name, value, constantSignatureToken);
}
catch (ArgumentException)
{
// writing the constant value into the PDB failed because the string value was most probably too long.
// We will report a warning for this issue and continue writing the PDB.
// The effect on the debug experience is that the symbol for the constant will not be shown in the local
// window of the debugger. Nor will the user be able to bind to it in expressions in the EE.
//The triage team has deemed this new warning undesirable. The effects are not significant. The warning
//is showing up in the DevDiv build more often than expected. We never warned on it before and nobody cared.
//The proposed warning is not actionable with no source location.
}
catch (Exception ex)
{
throw new PdbWritingException(ex);
}
Swallowing exceptions, tsk, tsk. It dies on the last catch clause in your case. They did dig a little deeper to reverse-engineer the string length problem:
internal const int PdbLengthLimit = 2046; // Empirical, based on when ISymUnmanagedWriter2 methods start throwing.
Which is fairly close to where the \0 starts throwing, I got 2034. Nothing much that you or anybody else here can do about this of course. All you can reasonably do is report the bug at connect.microsoft.com. But hopefully you see the writing on the wall, the odds that it will get fixed are rather small. This is code that nobody maintains anymore, it now has 'undocumented' status and judging from other comments this goes back long before .NET. Not Ed Maurer either :)
Workaround ought to be easy enough, glue this string together at runtime.
I was able to repro the issue as coded. Then I changed the declaration to:
const string history = #"aaa\0aaa...lots and lots of aaa...aaa";
Tried again and it compiles just fine.

Strange behaviour when comparing two strings with ==

I have observed a strange behaviour when comparing two strings with ==.
A little bit of context: The following code is from an application which should act as server and it should validate the thumbprint of the clientcertificate.
I have a client application with a certificate with the following thumbprint: "2074529C99D93D5955FEECA859AEAC6092741205". When I call the server this method returns Valid:
static CertificateValidationResult ValidateClientCertificate(X509Certificate2 clientcertificate)
{
return clientcertificate.Thumbprint == "‎2074529C99D93D5955FEECA859AEAC6092741205"
? CertificateValidationResult.Valid
: CertificateValidationResult.Rejected;
}
After I changed to a clientcertificate with the thumbprint "‎F9A021D2EFDCD3BD13671CE1D25CFE51BA5BA38E" and changed the server code the following method returns Rejected:
static CertificateValidationResult ValidateClientCertificate(X509Certificate2 clientcertificate)
{
return clientcertificate.Thumbprint == "‎F9A021D2EFDCD3BD13671CE1D25CFE51BA5BA38E"
? CertificateValidationResult.Valid
: CertificateValidationResult.Rejected;
}
In each case the strings are exactly the same, but only the first one returned Valid. Why is this happening?
If you copied / pasted the Thumbprint you may have accidentally copied a hidden character / symbol. Often these don't appear in the Visual Studio IDE even if you enable "Show Whitespace". This can cause all sorts of strange side-effects as you have witnessed.
The best approach is to manually type out the thumbprint into Visual Studio which will ensure no funny characters have slipped in. This can be a bit of a pain but the only way of guaranteeing you are actually comparing like for like.

Changing the value of a String in C# WinApp forever?

Assume I have a String Field in my WinApp like below :
public string UsingTheApplicationFrom =
"Not Yet";
Now , I wanna to change the value of the field forever, in first running of my application. e.g : UsingTheApplicationFrom = "‎Friday, ‎January ‎21, ‎2011";
Is it possible in C# WinApp ?
Could you please guide me?
Edit:
I don't wanna use Database or file or Registry or something else.
You are looking for "a type of security for my application that only the first system (that runs the application for the first time) could use my application". I think you mean that each copy of the software you sell may only be installed on one computer at a time.
You have two problems to solve:
How to generate a unique identifier for the computer
How to store the identifier value
You have several options to use for a unique identifier, none of which are great. Be prepared for support requests from customers when they change their computer hardware, when their computer breaks, or when they want to move the software from one computer to another. A decent-looking method to compute a unique identifier is this article (mirror link since the code project article is not available).
I would recommend just storing this identifier as a string in the app.config file (using Properties.Settings, start at this link for more information). It will be visible in plain text, but how would an unlicensed user know what value to change it to for their machine when it looks like "4876-8DB5-EE85-69D3-FE52-8CF7-395D-2EA9"? If it doesn't match direct them to your website/telephone for support.
You still have the problem of deciding when to set this value -- I would advocate for setting it as part of an installer instead of saving it the first time the program is run, since then you still have a problem to determine when the program is first run. The installer might need some sort of registration code and a method to communicate with a central licensing server. (Yes, this does get complicated -- how determined do you think people might be to hack your licensing?)
I am taking a guess, but by "always" I think he means "forever". You could easily create a key in the App.config of your application and populate it on the first run.
<add key="UsingTheApplicationForm" value="Not Yet"/>
On first run, update it to -
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings["UsingTheApplicationForm"].Value = DateTime.Now.ToShortDateString();
// Save the configuration file.
config.Save(ConfigurationSaveMode.Modified);
// Force a reload of a changed section.
ConfigurationManager.RefreshSection("appSettings");
On second run check if the key value is equal to "Not Yet". If it is not, it means that this is not the first run.
I think maybe you want to use DateTime, and particularly, DateTime.Now - as with comments to the question however, I'm not properly sure.
So, something like:
UsingTheApplicationForm = String.Format("{0:dddd, MMMM d, yyyy}", DateTime.Now);
The 'always' part is very confusing though, I'm just going to buy into my own translation, where always = each startup.
I would also conjecture that, given the property/variable name of UsingTheApplicationForm, this value is an indicative field, rather than a descriptive one; for this reason, may just using DateTime.Now without any formatting, or even just a boolean (depends what fits your situation) fit the bill?
Edit:
For information on using this method, or any of the others, along with persisting this data for the next run, see the following question and answers...
Editing app.config in execution time using the same App
I like this way:
http://windowsclient.net/blogs/suryahg/archive/2008/08/11/persist-winforms-application-settings.aspx
There's no way to do it with nothing more than a string object, but you can create a simple object that does it:
public class ApplicationInfo
{
private ApplicationStartTime()
{
this.StartTime = new DateTime().Now;
}
public DateTime StartTime
{
get; private set;
}
public Create()
{
return new ApplicationStartTime();
}
}
I haven't compiled that, so there may be a minor syntax error or two. You would invoke it like so:
var applicationInfo = ApplicationInfo.Create();
Debug.WriteLine(applicationInfo.StartTime.ToString());
In your program.cs or main entry point for the program declare a public static datetime.
when the program is first run you can set the date time and access it in future.
public static Datetime m_StartDate = DateTime.now;
public static void Main(args)
{
m_StartDate = DateTime.Now;
}
then in your other forms (assuming you added the code to Program.cs)
txtStartTime.Text = Program.m_StartDate.toString();

Categories