Spring MVC, #RequestParam initialize default list with one empty string - spring-mvc

Is there a way to initialize a default list with one empty string using the #RequestParam annotation in Spring MVC?
If I use the following code, the list is empty:
public String example(
#RequestParam(value = "example", defaultValue = "")
List<String> exampleList) {
return "";
}
Using defaultValue = "," instead, results in a list with two empty strings. My current solution is to check if the list is empty and if so add the empty string to it but is there a better way?

Instead of defaultValue = "," use defaultValue = " ". It's work and your list is initialise with one empty string.

Related

Newtonsoft Json JsonSerializationException with simple string

My datasource creates the JSON representing an array of integers as "1,2,3,4,5". I can't do anything about this (Like changing it to [1,2,3,4,5]), it is an enterprise CMS that we have to just deal with.
I'm trying to read up on how the newtonsoft ToObject method handles the following code:
JValue theValue = new JValue("1,2,3")
List<int> x = theValue.ToObject<List<int>>();
I get a Newtonsoft.Json.JsonSerializationException. Could not cast or convert from System.String to System.Collections.Generic.List`1[System.String]. I understand this fully, but I'd like to know if the Newtonsoft JSON libraries have a built in way to convert from a comma delimited string to a List.
I'd like to think there's a better way than trying to check if the variable is a comma delimited list or not and then converting it to a List<> manually, or maybe a JArray, but I've been wrong before !
EDIT
I wanted to share my solution:
dynamic theValue = new JValue("1,2,3,4"); /// This is just passed in, i'm not doing this on purpose. Its to demo.
if (info.PropertyType == typeof (List<int>))
{
if (info.CanWrite)
{
if (theValue.GetType() == typeof (JValue) && theValue.Value is string)
{
theValue = JArray.Parse("[" + theValue.Value + "]");
}
info.SetValue(this, theValue.ToObject<List<int>>());
}
} else {
// do other things
You have three problems from what I can see:
You should be using JArray not JValue. You are intending this to be an array of things, so you need to use the equivalent class in Newtonsoft to represent an array. (A JValue, as best I can tell, represents a simple type--e.g. string, number, Date, etc.)
You should use the Parse method versus using the constructor. Parse will read the content of the string as an array, however...
...in order for it to do that, you will need to surround the data that you get with the square brackets or JArray can't correctly the parse the data. There is no need to fiddle with the CMS; just do a string concat before you parse.
e.g.
JArray theValue = JArray.Parse("[" + "1,2,3" + "]");

change query string values without redirect in c#

I have a query string that looks something like this:
"somename1=123&QueryString=PlaceHolder%3dNothing%26anotherid%3dsomevalue&somename=somevalue"
but I want the query string to be something like the query string below and replace the whole query string with the updated one is there any way to do that without redirection?
"somename1=somevalue1&PlaceHolder=Nothing&somename2=somevalue2&somename3=somevalue3"
basically need to remove:
"QueryString=" with empty string
"%3d" with "&"
"%26" with "="
So far I've done is:
string strQueryString = Request.QueryString.ToString();
if (strQueryString.Contains("QueryString="))
{
strQueryString = strQueryString.Replace("QueryString=", "");
if (strQueryString.Contains("%26")) strQueryString = strQueryString.Replace("%26", "&");
if (strQueryString.Contains("%3d")) strQueryString = strQueryString.Replace("%3d", "=");
string x = strQueryString;
}
and:
// reflect to readonly property
PropertyInfo isreadonly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
// make collection editable
isreadonly.SetValue(this.Request.QueryString, false, null);
if (this.Request.QueryString.ToString().Contains("QueryString="))
{
this.Request.QueryString.ToString().Replace("QueryString=", "");
if (this.Request.QueryString.ToString().Contains("%26")) this.Request.QueryString.ToString().Replace("%26", "&");
if (this.Request.QueryString.ToString().Contains("%3d")) this.Request.QueryString.ToString().Replace("%3d", "=");
string x = this.Request.QueryString.ToString();
}
// make collection readonly again
isreadonly.SetValue(this.Request.QueryString, true, null);
The second part of the code is not replacing the characters and I don't know how after removing all character or replacing them change the query string to new query string.
Any help is greatly appreciated.
Changing the query string of the current request is not supported. Using private Reflection to edit some in-memory state will most likely break ASP.NET because it assumes that the query string is immutable. The only way to change the query string is to issue a new request, either by doing a redirect, or by doing a sort of sub-request, such as by making a new HTTP request to the same page but with a different query string.
May I suggest a not very well known built in key/value dictionary, Context.Items.
With this you very like get a better performance than toggle the readonly QueryString object, and it also last throughout a request so you can share it between module, handlers, etc.
Create
string strQueryString = Request.QueryString.ToString();
if (strQueryString.Contains("QueryString="))
{
HttpContext.Current.Items("qs") = strQueryString.Replace("QueryString=", "").Replace("%26", "&").Replace("%3d", "=");
}
Use
string x = HttpContext.Current.Items("qs_d").ToString();
Side note: I shortened you code some, as there is no need to first check if anything contains and if so, replace, just run replace, it will be faster

Looks like a query string, but won't act as a query string

I am working with VB in asp.net,
The basic problem is, I want to pair up the elements in a string, exactly like request.QueryString() will do to the elements in the query string of the web page.
However instead of the function looking at the current webpage query string I want it to look at a string (that is in the exact form of a query string) stored as a variable.
So if I define a string such as:
Dim LooksLikeAQueryString As String = "?category1=answer1&category2=answer2"
I want a function that if I input LooksLikeAQueryString and "category1" it outputs "answer1" etc.
Is there anything that can already do this or do I have to build my own function? If I have to build my own, any tips?
I should add that in this case I won't be able to append the string to the url and then run request.QueryString.
You can use the HttpUtility.ParseQueryString method - MSDN link
ParseQueryString will do it for you - something along these lines:
Private Function QueryStringValue(queryString As String, key As String) As String
Dim qscoll As NameValueCollection = HttpUtility.ParseQueryString(queryString)
For Each s As String In qscoll.AllKeys
If s = key Then Return qscoll(s)
Next
Return Nothing
End Function
Usage:
Dim LooksLikeAQueryString As String = "?category1=answer1&category2=answer2"
Response.Write(QueryStringValue(LooksLikeAQueryString, "category2"))
If you dont want the dependancy of System.Web, of the top of my head
public string GetValue(string fakeQueryString,string key)
{
return fakeQueryString.Replace("?",String.Empty).Split('&')
.FirstOrDefault(item=>item.Split('=')[0] == key);
}

Change Single URL query string value

I have an ASP.NET page which takes a number of parameters in the query string:
search.aspx?q=123&source=WebSearch
This would display the first page of search results. Now within the rendering of that page, I want to display a set of links that allow the user to jump to different pages within the search results. I can do this simply by append &page=1 or &page=2 etc.
Where it gets complicated is that I want to preserve the input query string from the original page for every parameter except the one that I'm trying to change. There may be other parameters in the url used by other components and the value I'm trying to replace may or may not already be defined:
search.aspx?q=123&source=WebSearch&page=1&Theme=Blue
In this case to generate a link to the next page of results, I want to change page=1 to page=2 while leaving the rest of the query string unchanged.
Is there a builtin way to do this, or do I need to do all of the string parsing/recombining manually?
You can't modify the QueryString directly as it is readonly. You will need to get the values, modify them, then put them back together. Try this:
var nameValues = HttpUtility.ParseQueryString(Request.QueryString.ToString());
nameValues.Set("page", "2");
string url = Request.Url.AbsolutePath;
string updatedQueryString = "?" + nameValues.ToString();
Response.Redirect(url + updatedQueryString);
The ParseQueryString method returns a NameValueCollection (actually it really returns a HttpValueCollection which encodes the results, as I mention in an answer to another question). You can then use the Set method to update a value. You can also use the Add method to add a new one, or Remove to remove a value. Finally, calling ToString() on the name NameValueCollection returns the name value pairs in a name1=value1&name2=value2 querystring ready format. Once you have that append it to the URL and redirect.
Alternately, you can add a new key, or modify an existing one, using the indexer:
nameValues["temp"] = "hello!"; // add "temp" if it didn't exist
nameValues["temp"] = "hello, world!"; // overwrite "temp"
nameValues.Remove("temp"); // can't remove via indexer
You may need to add a using System.Collections.Specialized; to make use of the NameValueCollection class.
You can do this without all the overhead of redirection (which is not inconsiderable). My personal preference is to work with a NameValueCollection which a querystring really is, but using reflection:
// reflect to readonly property
PropertyInfo isReadOnly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
// make collection editable
isReadOnly.SetValue(this.Request.QueryString, false, null);
// remove
this.Request.QueryString.Remove("foo");
// modify
this.Request.QueryString.Set("bar", "123");
// make collection readonly again
isReadOnly.SetValue(this.Request.QueryString, true, null);
Using this QueryStringBuilder helper class, you can grab the current QueryString and call the Add method to change an existing key/value pair...
//before: "?id=123&page=1&sessionId=ABC"
string newQueryString = QueryString.Current.Add("page", "2");
//after: "?id=123&page=2&sessionId=ABC"
Use the URIBuilder Specifically the link textQuery property
I believe that does what you need.
This is pretty arbitrary, in .NET Core at least. And it all boils down to asp-all-route-data
Consider the following trivial example (taken from the "paginator" view model I use in virtually every project):
public class SomeViewModel
{
public Dictionary<string, string> NextPageLink(IQueryCollection query)
{
/*
* NOTE: how you derive the "2" is fully up to you
*/
return ParseQueryCollection(query, "page", "2");
}
Dictionary<string, string> ParseQueryCollection(IQueryCollection query, string replacementKey, string replacementValue)
{
var dict = new Dictionary<string, string>()
{
{ replacementKey, replacementValue }
};
foreach (var q in query)
{
if (!string.Equals(q.Key, replacementKey, StringComparison.OrdinalIgnoreCase))
{
dict.Add(q.Key, q.Value);
}
}
return dict;
}
}
Then to use in your view, simply pass the method the current request query collection from Context.Request:
<a asp-all-route-data="#Model.NextPageLink(Context.Request.Query)">Next</a>

ASP.Net Mapping Values Lookup

Currently in my ASP.Net applications web.config I have an application setting that stores a comma delimited list of mapping values, like the one below. In the code behind I need to perform a lookup on this data based on input values 1, 2, 3 etc. I can either string split it and loop until I find a match, or use Regex to pull the value from the config string.
Currently i'm using Regex to get the mapping value. I'm not opposed to changing how the data is stored in the web.config. Is there a more simple and elegant way of handling this?
<add key="Mappings" value="1|APP,2|TRG,3|KPK,4|KWT,5|CUT" />
If you need to use this lookup frequently and the string in web.config doesn't change very often, then it makes sense to parse the string once into a Dictionary object and store that in the Application or Cache.
Lookups from the Dictionary will be lightning fast, especially compared to parsing the string each time.
private static readonly object _MappingsLock = new object();
public static string GetMapping(int id)
{
// lock to avoid race conditions
lock (_MappingsLock)
{
// try to get the dictionary from the application object
Dictionary<int, string> mappingsDictionary =
(Dictionary<int, string>)Application["MappingsDictionary"];
if (mappingsDictionary == null)
{
// the dictionary wasn't found in the application object
// so we'll create it from the string in web.config
mappingsDictionary = new Dictionary<int, string>();
foreach (string s in mappingsStringFromWebConfig.Split(','))
{
string[] a = s.Split('|');
mappingsDictionary.Add(int.Parse(a[0]), a[1]);
}
// store the dictionary in the application object
// next time around we won't need to recreate it
Application["MappingsDictionary"] = mappingsDictionary;
}
// now do the lookup in the dictionary
return mappingsDictionary[id];
}
}
// eg, get the mapping for id 4
string mapping = GetMapping(4); // returns "KWT"
Just curious :) What about LINQ
string inputValue = "2";
string fromConfig = "1|APP,2|TRG,3|KPK,4|KWT,5|CUT";
string result = fromConfig
.Split(',')
.Where(s => s.StartsWith(inputValue))
.Select(s => s.Split('|')[1])
.FirstOrDefault();
Or
Regex parseRegex = new Regex(#"((?<Key>\d)\|(?<Value>\S{3}),?)");
parseRegex.Matches(fromConfig)
.Cast<Match>()
.Where(m => m.Groups["Key"].Value == inputValue)
.Select(m => m.Groups["Value"].Value)
.FirstOrDefault();
Split the string on commas, then each substring on |, store these in a Dictionary and find it by key.
That's just as an alternative to Regex. You know what they say about Regex.

Resources