For security reasons, I don't want specific method to receive non-programmer or non-compiler time strings, how could I do this?
readonly String OK_STR = "some text";
String BAD_STR = "another text";
public void SetSecureStr(String str)
{
//Use the string for security purpose
}
//Somewhere in the code
SetSecureStr(OK_STR); //Accepted
SetSecureStr(OK_STR + "Programmer passed this staticlly!"); //Accepted (If not possible to implement, forget about it)
SetSecureStr(BAD_STR); //Throw exception, BAD_STR is modifiable
SetSecureStr(OK_STR + untrustedVar); //Throw exception, concatenation with modifiable
SetSecureStr(String.Format("{0}", OK_STR)); //Throw exception, not const
It may be better to whitelist against things inside your ability to control, such as enums or local constants (or a local whitelist from configuration data if the list isn't fixed ahead of time).
As a rough check, you could check whether it is interned, since all literals will be interned automatically via ldstr; but note you can explicitly intern too, so this isn't 100% safe.
And of course, in any event with the question as asked, if that string happens somewhere else as a literal (unconnected to this code) it would still be trusted. I suggest a whitelist is safer...
A whitelist could be as simple as:
private static readonly HashSet<string> whiteList = new HashSet<string> {
"good", "more good"
};
... check via whiteList.Contains(s)
but note that this is still mutable at runtime (via reflection if necessary).
Instead of accepting string values, number all your strings, and pass the number:
string[] good_strings = {"some text"};
public void SetSecureStr(int stringno)
{
string s = good_strings[stringno];
}
Computed strings won't be supported with that approach.
I came finally with a solution which is hybrid between the two previously proposed answers:
public class SqlQuery
{
private SqlQuery() { }
private static UInt32 sqlQueriesCount = 0;
public static UInt32 INBOUND_UPDATE_CALLBACK_NUM = sqlQueriesCount++;
public static UInt32 INBOUND_UPDATE_DEST_ADDR_SUBUNIT = sqlQueriesCount++;
public static UInt32 INBOUND_UPDATE_DEST_BEARER_TYPE = sqlQueriesCount++;
//...etc
private static readonly Dictionary<UInt32, String> queries = new Dictionary<UInt32, String>
{
{SqlQuery.INBOUND_UPDATE_CALLBACK_NUM, "UPDATE inbound SET callbackNum = ? WHERE id = ?"},
{SqlQuery.INBOUND_UPDATE_DEST_ADDR_SUBUNIT, "UPDATE inbound SET destAddrSubunit = ? WHERE id = ?"},
{SqlQuery.INBOUND_UPDATE_DEST_BEARER_TYPE, "UPDATE inbound SET destBearerType = ? WHERE id = ?"},
//...etc
};
public static String GetQueryText(UInt32 queryKey)
{
String query = null;
if (SqlQuery.queries.TryGetValue(queryKey, out query) == false)
{
throw new ArgumentOutOfRangeException(String.Format("Query must be paramerized query stored within SqlQuery class, provided queryKey: {0}", queryKey));
}
return query;
}
}
Usage:
OdbcCommand cmd = new OdbcCommand(SqlQuery.GetQueryText(SqlQuery.INBOUND_UPDATE_CALLBACK_NUM), con);
Related
We are currently working on a logging solution and have implemented an extension method call 'Log'. When writing to the log file, we would ideally like to write the original variable name (rather than the variable name used in the extension method).
What we are currently having to do for this is:
public void DoSomeWork()
{
String testString = "Hey look I'm a string!";
testString.Log("testString value");
}
With the extention method:
public static String Log(this String valueToStore, String name)
{
// The logging code which uses the 'name' parameter
}
The issue here is that it becomes difficult to read on longer lines of code and looks clustered. What would be ideal is this:
public void DoSomeWork()
{
String testString = "Hey look I'm a string!";
testString.Log();
}
With the extension method:
public static String Log(this String valueToStore)
{
// The logging code which is able to retrieve the
// value 'testString' from the 'valueToStore' value
}
Is this at all possible by using Reflection? I'm aware of the nameofoption, but that only returns the string 'valueToStore' when used in the extension method.
Well, short answer is no. The variable names are not guaranteed to persist after compilation in unchanged form. That information would have to be somehow persisted (for example by the use of nameof()). Also, the variable name might not exist ("test".GetVarName()).
The long answer is: yes, possibly, but it's one of the most ridiculous things I've created in my life:
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace Test1
{
class Program
{
static void Main(string[] args)
{
var myVarName = "test";
myVarName.Test();
Console.ReadKey();
}
}
static class Extensions
{
public static void Test(
this string str,
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0
)
{
var relevantLine = File.ReadAllLines(sourceFilePath)[sourceLineNumber-1];
var currMethodName = MethodInfo.GetCurrentMethod().Name;
var callIndex = relevantLine.IndexOf(currMethodName + "()");
var sb = new Stack<char>();
for (var i = callIndex - 2; i >= 0; --i)
{
if (Char.IsLetterOrDigit(relevantLine[i]))
{
sb.Push(relevantLine[i]);
}
}
Console.WriteLine(new String(sb.ToArray()));
}
}
}
C# 10 has CallerArgumentExpressionAttribute that will do just that
public static void PrintNameAndValue(
this object obj,
[System.Runtime.CompilerServices.CallerArgumentExpression("obj")] string callerExp = ""
)
{
Console.WriteLine(callerExp + " = " + obj.ToString());
}
It'll capture the entire expression passed:
public void TestPrintNameAndValue()
{
string mystring = "test";
int myint = 5;
mystring.PrintNameAndValue(); // mystring = test
myint.PrintNameAndValue(); // myint = 5
(myint + 10).PrintNameAndValue(); // myint + 10 = 15
mystring.ToUpper().PrintNameAndValue(); // mystring.ToUpper() = TEST
}
You can use an Expression to achieve that, but performance-wise it may not be the best option:
public static void Log<T>(Expression<Func<T>> expr)
{
var memberExpr = expr.Body as MemberExpression;
if (memberExpr == null)
return;
var varName = memberExpr.Member.Name;
var varData = expr.Compile()();
// actual logging
...
}
Usage:
var test = "Foo";
Log(() => test);
Alternatively, if you're using C# 6.0, it can get a bit better using the nameof operator:
test.Log(nameof(test));
A better solution would be one that is leveraging the compiler abilities (specifically, the "Roslyn" compiler) and provide the member name on compile time.
Not really an answer, more of a pointer, but you could try doing something with your application that you're using(e.g. visual studio) instead of doing it in code. What I mean is make it rewrite everything that looks like [variable].Log(); to [variable].Log([variable])
I am pretty sure that there has to be some weird macro or plugin which does this for you before compiling.
I need to download regularly the data from link like below and save it to the MS database. I made CLR function with WebClient class but everythig is in one row, I need to separate it.
I got the idea to save the data in the array, use split and return it in loop but I don't know how to return line by line to save it in database.
public partial class UserDefinedFunctions
{
private static readonly WebClient webClient = new WebClient();
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString DownloadSynop(string uri)
{
string synop = webClient.DownloadString(uri);
string[] lines = synop.Split(new string[] { Environment.NewLine, "\n", "\"r" }, StringSplitOptions.None);
for (int i=0; i<lines.Length - 1; i++)
{
string kod = lines[i];
}
return new SqlString(kod); //problem
}
}
SQL Server does not really support “Arrays” per say and in general I would recommend that you develop a separate service or application that parses the web page and then simply insert the needed data into a table formatted for your needs. Using a CLR to query a web page means that you would have to publish the CLR as Unsafe to SQL Server. Some organization will not allow CLR’s marked as unsafe on their servers.
Having said that you can create a table valued CLR function. This will allow you to query your result from your function like a standard table. Below is a code example of how you can achieve this:
public partial class UserDefinedFunctions
{
private struct Record
{
public int RowNr;
public string SampleValue;
}
[SqlFunction(FillRowMethodName = "MyClrTableValuedFunction_FillRow",
TableDefinition = "[RowNr] INT, [SampleValue] NVARCHAR(50)")]
public static IEnumerable MyClrTableValuedFunction()
{
ArrayList list = new ArrayList();
for (int sampleRowNr = 0; sampleRowNr < 100; sampleRowNr++)
{
Record sampleRecord = new Record();
sampleRecord.RowNr = sampleRowNr;
sampleRecord.SampleValue = string.Format("Sample Value: {0}", sampleRowNr);
list.Add(sampleRecord);
}
return list;
}
public static void MyClrTableValuedFunction_FillRow(Object obj, out SqlInt32 rowNr, out SqlString sampleValue)
{
Record record = (Record)obj;
rowNr = record.RowNr;
sampleValue = record.SampleValue;
}
}
You can call your function as a standard select statement in SQL Server as follow:
SELECT [RowNr]
,[SampleValue]
FROM [dbo].[MyClrTableValuedFunction]()
This is my syntax, but it is not being passed to my connection string, it is being omitted, which of course is causing an error as the database doesn't exist. Is it possible to do this?
namespace bottomsup
{
class onetwothree
{
private static string databaseName = null;
private static string ServerConnectionString = "Data Source=BradJohnson;Initial Catalog=" + databaseName + "DB;User ID = pmartin;Integrated Security=True;MultipleActiveResultSets=True"";
Form1()
{
InitializeComponents();
}
private void ConnectToServerClick()
{
databaseName = textbox1.Text;
using (SqlConnection connection = new SqlConnection(ServerConnectionString))
{
connection.Open();
//more stuff
}
}
}
}
No, if you change the value of databaseName later on, it doesn't automatically change the value of ServerConnectionString.
You have to set the value of ServerConnectionString again yourself.
ServerConnectionString =
string.Format("Data Source=BradJohnson;Initial Catalog={0}DB;User ID = pmartin;Integrated Security=True;MultipleActiveResultSets=True", textbox1.Text);
I'd avoid the static variable, as it can lead to bugs if you try to reuse it, and especially if you overwrite it, in multiple places. One place sets it, then another, and now one or the other is going to grab an incorrect value when it tries to retrieve it.
Perhaps something like this instead, where you always have to pass the database name in:
private static string GetServerConnectionString(string databaseName)
{
return string.Format("Data Source=BradJohnson;Initial Catalog={0}DB;User ID = pmartin;Integrated Security=True;MultipleActiveResultSets=True", databaseName);
}
To use it with your existing code:
using (var connection = new SqlConnection(GetServerConnectionString(textbox1.Text)))
{
connection.Open();
//more stuff
}
I doubt if statics are justified in this case.
Nevertheless, it will not work with variable ServerConnectionString, but you could use a property instead:
private static string ServerConnectionString
{
get
{
return "Data Source=BradJohnson;Initial Catalog=" + databaseName +
"DB;User ID = pmartin;Integrated Security=True;MultipleActiveResultSets=True";
}
}
Often when you try to add a null value to something which has a value, it will fall over. In the DB Name you should use String.Empty as opposed to null.
Also I think you have an extra quote on the end of the string.
When you set the connection string, it is not going to dynamically update if you ever change the other property anyway.
public class RegistrationClass
{
SqlConnection myConnection = new SqlConnection("Data Source=MOE-PC\\SQLEXPRESS;Initial Catalog=db_University;Integrated Security=True;Pooling=False");
ConnectionClass con = new ConnectionClass();
int ID , i;
String fullName, motherName, gender, placeOfBirth, email, phone, adress, schoolDegree, languages, highSchool, faculty, major;
public void setValues (String fullName1,String motherName1,String gender1,String placeOfBirth1,String email1,String phone1,String adress1, String faculty1,String major1,String schoolDegree1,String languages1,String highSchool1)
{
fullName = fullName1;
motherName = motherName1;
gender = gender1;
placeOfBirth= placeOfBirth1;
email =email1;
phone= phone1;
adress =adress1;
faculty =faculty1;
major =major1;
schoolDegree =schoolDegree1;
languages =languages1;
highSchool = highSchool1;
}
This is the webform on register button click
public partial class WebForm1 : System.Web.UI.Page
{
protected void Button_Register_Click(object sender, EventArgs e)
{
string lang = "";
Classes.RegistrationClass R = new Classes.RegistrationClass();
R.setValues(txt_Name.ToString, txt_MotherName.ToString, dropDown_Gender.ToString, dropDown_POB.ToString, txt_Email.ToString, txt_Phone.ToString, txt_Adress.ToString, DropDown_Faculty.ToString, DropDown_Major.ToString, dropDown_SchoolDegree.ToString, txt_Name.ToString, txt_HighSchool.ToString);
Here is the error:
The best overloaded method match for 'CCharpApp.RegistrationClass.setValues(string,string,string,string,string,string,string,string,string,string,string,string)' has some invalid arguments.
This can also happen when a dynamic variable is passed into the method as an argument. The compiler compiles without an error, there can be an execution error.
txt_Name.ToString resolves to a method group that refers to the ToString method. It doesn't call ToString. To do that you would need to write txt_Name.ToString(). Having said that, you don't want to do that either. The ToString method of TextBox does not return the text of the control. The Text property is how you get the text, so you want to write: txt_Name.Text.
Finally, you should avoid functions with so many arguments. It makes it much harder to try to determine what's wrong when you have the error that you are seeing when there are so many arguments; there are just so many ways that it could be off. Instead RegistrationClass should simply have properties of each of those values, and then the caller can set each property individually. This will be quite a lot easier to work with.
i had a same issue, solved as following.
dynamic postdata = new ExpandoObject();
postdata.player_name = player;
postdata.bidder_id = bidder;
postdata.bid_price = price;
postdata.status = "Sold";
This code is not valid:
private void Foo(string optionalString = string.Empty)
{
// do foo.
}
But this code is:
private void Foo(string optionalString = "")
{
// do foo.
}
Why? Because string.Empty is a readonly field, not a constant, and defaults for optional parameters must be a compile-time constant.
So, onto my question... (well, concern)
This is what i've had to do:
private const string emptyString = "";
private void Foo(string optionalString = emptyString)
{
// do foo.
if (!string.IsNullOrEmpty(optionalString))
// etc
}
How do you guys handle optional string parameters?
Why can they not make String.Empty a compile-time constant?
Ummm... what's wrong with string optionalParm = "" again? Why is that bad? Do you really think you need a symbolic constant for an empty string in this case? How about this then?
const int Zero = 0;
void SomeMethod(int optional = Zero) { }
Does that seem at all silly to you?
if you don't like "" value you can use default(string).
I played with it and it is allowed.
private static void foo(string param = default(string)) {
if (!string.IsNullOrEmpty(param)) // or param != default(string)
Console.WriteLine(param);
}
Code Analysis warning 1026 says not to use optional parameters. It's better style to use overload methods, like this:
private void Foo()
{
Foo(string.Empty);
}
private void Foo(string optionalString)
{
// do foo.
if (!string.IsNullOrEmpty(optionalString))
// etc
}
The best way to handle them is with:
private void Foo(string optionalString = "")
{
// do foo.
}
So you can't use String.Empty. Everyone recognizes "", but if I found optionalString = nullString I wouldn't be sure what to think. If nothing else, name the thing emptyString--it's not null!
I'm answering this question.
Why can they not make String.Empty a compile-time constant?
Here is the disassemble code via Reflector of String.cs in mscorlib.dll
public static readonly Empty;
static String()
{
Empty = "";
WhitespaceChars = new char[] {
'\t', '\n', '\v', '\f', '\r', ' ', '\x0085', '\x00a0', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', '', '\u2028', '\u2029', ' ', ''
};
}
So in windows platform, string.Empty is exactly "". But do you know, Martian have a different definition for Empty and WhitespaceChars in their OS.
If you are willing to play lose and treat null, "", and whitespace characters to be the same, then you can default to null. This becomes very handy when user name and password are optional fields due to a possibility of trusted connection to a db. You could change this logic to reset strings to null and thus modify the assert and the if. The important part is having a consistent convention.
private void RunSql(string serverName, string databaseName, string userName = null, string password = null)
{
userName = Strip(userName);
password = Strip(password);
// The `MsTest` assert - works in both `Debug` and `Release` modes.
Assert.AreEqual<bool>(
userName == String.Empty,
password == String.Empty,
"User name and password should be either both empty or both non-empty!");
Assert.IsFalse(String.IsNullOrWhiteSpace(serverName));
Assert.IsFalse(String.IsNullOrWhiteSpace(databaseName));
var cmdBuilder = new StringBuilder();
cmdBuilder.AppendFormat("sqlcmd -E -S {0} -d {1} ", serverName, databaseName);
if (userName.Length > 0)
{
cmdBuilder.AppendFormat("-U {0} -P {1} ", userName, password);
}
// Complete the command string.
// Run the executable.
}
// Cannot think of a good name. Emptify? MakeNullIfEmpty?
private string Strip(string source)
{
if (String.IsNullOrWhiteSpace(source))
{
return String.Empty;
}
return source;
}