Springboot application property with placeholder which is updated dynamically inside app - spring

Is there a way in which i can have a property in my application.properties file which can be holding a property with a placeholder which can later be populated inside the app?
Example (in below example {ID} is the place holder which is changed later in app):
application.properties
url.fetch.data.with.id=http://localhost:8080/data/{ID}/details
Which can then be used inside the application as below:
#Value("${url.fetch.data.with.id}")
String dataUrl;
String makeUrl(String id) {
return dataUrl.replace("{ID}", id);
}
In above I use String class replace() function to replace {ID} with id
Are there any functionalities provided by Springboot to achieve this result where I can dynamically change a part of my property inside the app?

This can be achieved easily.
#Value("${url.fetch.data.with.id}")
String dataUrl;
String makeUrl(String id) {
return UriComponentsBuilder.fromHttpUrl(dataUrl).buildAndExpand(id).toString();
}
using the above code, if the URL has multiple placeholdets, add the values to be substituted in order.
url.fetch.data.with.id=http://localhost:8080/data/{ID}/details/{detailed}?startDate={startDate}&end={endDate}
long startDate = java.time.Instant.now().toEpochMilliSeconds();
long EndDate = java.time.Instant.now().toEpochMilliSeconds();
String detailedId = "abc";
String makeUrl(String id) {
return UriComponentsBuilder.fromHttpUrl(dataUrl).buildAndExpand(id,detailedId,startDate,EndDate).toString();
}

Related

Execute a simple call to a WebAPI Get using RestRequest and a single string parameter

I have the following code in my receiving controller:
[Route("api/StudentUserId/{string}"), HttpGet]
public StudentDto StudentUserId(string userId)
{
StudentModel sm = new StudentModel(userId);
StudentDto dto = sm.ConvertToDto();
return dto;
}
After running this project, I have another project that I use to test the WebAPI controller calls. I use the following code to read a student record form the database using their userId:
protected T SendRequestToReadItemUsingString<T>(string resource, string userId) where T : new()
{
string resourceString = string.Format("{0}/{{userId}}", resource);
RestRequest request = new RestRequest(resourceString, Method.GET);
request.AddUrlSegment("userId", userId);
RestClient restClient = new RestClient(Service.Location);
var response = restClient.Execute<T>(request);
T retVal = response.Data;
return retVal;
}
Comparible code seems to work if I change the userId to an int Id in both the controller and calling code. I can't seem to get it to work with string. If I place a breakpoint in the controller code it never hits it and the calling code just returns a null.
Thanks for your help
Please note that WebApi works based on reflection this means that your curly braces {vars} must match the same name in your methods.
Therefore to match this api/StudentUserId/{string} your method needs to be declare like this:
[Route("api/StudentUserId/{userId}"), HttpGet]
public StudentDto StudentUserId(string userId)
return userId;
}
Where the parameter {string} was replaced by userId.
If you want to read more about this Routing Rules here is similar post on this;
WebApi Routing Configuration

Regarding writing custom html helper for hidden field with few good feature ASP.Net MVC

this way i can write custom helper for hidden field
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Linq.Expressions;
namespace CustomHtmlHelpers.CustomHelpers
{
public static class CustomHiddenHelperModelBinding
{
//This overload accepts single expression as parameter.
public static MvcHtmlString Custom_HiddenFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
{
return Custom_HiddenFor(helper, expression, null);
}
//This overload accepts expression and htmlAttributes object as parameter.
public static MvcHtmlString Custom_HiddenFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
{
//Fetching the metadata related to expression. This includes name of the property, model value of the property as well.
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
//Fetching the property name.
string propertyName = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
//Creating a textarea tag using TagBuilder class.
TagBuilder hidden = new TagBuilder("input");
//Setting the type attribute to hidden to render hidden input field.
hidden.Attributes.Add("type", "hidden");
//Setting the name and id attribute.
hidden.Attributes.Add("name", propertyName);
hidden.Attributes.Add("id", propertyName);
//Setting the value attribute of textbox with model value if present.
if (metadata.Model != null)
{
hidden.Attributes.Add("value", metadata.Model.ToString());
}
//merging any htmlAttributes passed.
hidden.MergeAttributes(new RouteValueDictionary(htmlAttributes));
return MvcHtmlString.Create(hidden.ToString(TagRenderMode.Normal));
}
}
}
later we can access it like
#Html.Custom_HiddenFor(Model => Model.hidden)
#Html.Custom_HiddenFor(Model => Model.hidden, new { #class = "hiddenClass" })
my objective to rewrite my own html helper for hidden field is to render value at client side as encrypted text and as well as tamper proof.
if anyone tamper data then i want to check at server side and if tamper then i will show friendly error message to user.
this is another sampe code for encryption with machine key but i am not sure the that code works fine in partial trust environment or not?
here is the sample code
string Protect(byte[] data)
{
if (data == null || data.Length == 0) return null;
return MachineKey.Encode(data, MachineKeyProtection.All);
}
byte[] Unprotect(string value)
{
if (String.IsNullOrWhiteSpace(value)) return null;
return MachineKey.Decode(value, MachineKeyProtection.All);
}
here’s the 4.5 usage (it supports a slightly more sophisticated usage)
-------------------------------------------------------------------------
const string MachineKeyPurpose = "MyApp:Username:{0}";
const string Anonymous = "<anonymous>";
string GetMachineKeyPurpose(IPrincipal user)
{
return String.Format(MachineKeyPurpose,
user.Identity.IsAuthenticated ? user.Identity.Name : Anonymous);
}
string Protect(byte[] data)
{
if (data == null || data.Length == 0) return null;
var purpose = GetMachineKeyPurpose(Thread.CurrentPrincipal);
var value = MachineKey.Protect(data, purpose);
return Convert.ToBase64String(value);
}
byte[] Unprotect(string value)
{
if (String.IsNullOrWhiteSpace(value)) return null;
var purpose = GetMachineKeyPurpose(Thread.CurrentPrincipal);
var bytes = Convert.FromBase64String(value);
return MachineKey.Unprotect(bytes, purpose);
}
another way to encrypt
To generate a random string, use the RNGCryptoServiceProvider.
public string GenerateSalt(int length)
{
var rng = new RNGCryptoServiceProvider();
var buffer = new byte[length];
rng.GetBytes(buffer);
return Convert.ToBase64String(buffer);
}
Now we can generate a hashed password using the function below
public virtual string CreatePasswordHash(string password, string saltkey, string passwordFormat = "SHA1")
{
if (String.IsNullOrEmpty(passwordFormat))
passwordFormat = "SHA1";
string saltAndPassword = String.Concat(password, saltkey);
string hashedPassword =
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPassword, passwordFormat);
return hashedPassword;
}
so guide me how can i rewrite my own custom html helper which will encrypt data in most secure way and later which can be check to make sure the
value is tamper or not at client side.
i have another requirement to easily decrypt the value when form will post and action method will be called.
i want to decrypt the encrypted value using a attribute on action method. i want to fire a function will fire before action method and decrypt
value before data de-serialize to model or to action method argument.
is it possible ?
i want that my action method would look like
[HttpPost]
[Decrypt]
public ActionResult Save(string personname, string email)
{
return View();
}
or
[HttpPost]
[Decrypt]
public ActionResult Save(Person oPerson)
{
return View();
}
i want that my [Decrypt] attribute will fire a method call decypt and pass all value to decypt() function just before action method Save would invoke.
if decypt() function found any encrypted value then it will decrypt and de-serialize decypted value to model or to action method argument.
so i have three requirements
1) i want to write a custom html helper which will render hidden field with encrypted value.
2) when data post to server there i can detect that value has been tamper or not.
if tamper then a error page with proper message will be shown to user.
3)
action method will have custom attribute which will invoke a function before action method execution.
that function will decrypt value if any encrypted value found. after decryption the decrypted value will be properly De-serialize to model
or other action method argument properly.
i am new in MVC. so guide me how should i move forward with sample code. thanks
What about #Html.AntiForgeryToken()?
"Generates a hidden form field (anti-forgery token) that is validated when the form is submitted." Developer Network
Example:
1. In your markup add #Html.AntiForgeryToken() to the form.
2. Add [ValidateAntiForgeryToken] attribute your controller action.
Developer Network

How do I access data driven values in a web test plugin

I have a data driven web performance test in Visual Studio 2012. I want to access the values from the data source within a PreRequest() or a PostRequest() plugin. The values are being accessed already for form post parameters via bindings like {{DataSource1.PaymentAccounts#csv.USER_ID}}.
My end goal is to write the values into a web log comment so the data source values of failed tests are easier to identify. So the values would be passed into a call of e.WebTest.AddCommentToResult(string.Format(...)).
The values are stored in the text context, so can just access the value with WebTestRequestPlugin code such as:
object contextParameterObject;
if ( e.WebTest.Context.TryGetValue("DataSource1.PaymentAccounts#csv.USER_ID",
out contextParameterObject) ) {
string contextParameter = contextParameterObject.ToString();
e.WebTest.AddCommentToResult(contextParameter);
}
else {
throw new WebTestException("'DataSource1.PaymentAccounts#csv.USER_ID' not found");
}
By default the context only holds those fields (columns) of the data source that are explicitly used in the web test file. To make all the fields in the datasource available set the Select columns property of the datasource file to Select all columns.
[Description("Captures the datasource value used in a request and writes it to a file.")]
public class WriteDataSourceValueToFile : WebTestRequestPlugin
{
[Description("The name of the file to save the scraped values to. E.g., ResponseTimes.log. ")]
public string OutputFileName { get; set; }
[Description(#"Path of the file to save the scraped values to. Format: C:\temp. (Note no trailing backslash.)")]
public string OutputPathName { get; set; }
// The LogWriter class is in the main project, not in the utilities project.
private LogWriter writer = LogWriter.Instance;
[System.ComponentModel.Description("Name of the datasource.")]
[System.ComponentModel.DefaultValue("UserIds")]
public string DatasourceName { get; set; }
[System.ComponentModel.Description("Name of the CSV file. Use the syntax that Visual Studio uses, with a # sign in place of the period. E.g., UserIds#csv")]
[System.ComponentModel.DefaultValue("UserIds#csv")]
public string CsvFileName { get; set; }
[System.ComponentModel.Description("Field name in the CSV file")]
[System.ComponentModel.DefaultValue("UserIds")]
public string FieldName { get; set; }
public override void PreRequest(object sender, PreRequestEventArgs e)
{
}
public override void PostRequest(object sender, PostRequestEventArgs e)
{
object contextParameterObject;
if (e.WebTest.Context.TryGetValue(DatasourceName + "." + CsvFileName + "." + FieldName,
out contextParameterObject))
{
writer.WriteToLog($"Value chosen from {DatasourceName } ={contextParameterObject.ToString()}" );
}
else
{
throw new WebTestException(DatasourceName + "." + CsvFileName + "." + FieldName + " not found");
}
}
}
Two crucial Tips:
Beware lack of ANSI! Make sure you have saved the DS file (csv file) as ANSI per this stackoverflow post. Those unicode byte order marks at the beginning will make it difficult to refer to the column name when you write the DS string.
"DataSource1.mycsvfile#csv.myDSColumnName" is so much better than:
"DataSource1.mycsvfile#csv.myDSColumnName"
Then, in addition to trygetvalue (which is good) you should also simply be able to write:
string currentRowFromDS = e.WebTest.Context["DataSource1.mycsvfile#csv.myDSColumnName"].ToString();
After adding the DS to the webtest, be sure to change the "Select Columns" property to "Select all Columns" (and NOT "select only bound columns"). If you leave it at the default, "select only bound columns," and you have not actually bound the columns yet, Visual Studio will NOT place the row value into the web test. The context parameter will not be there at all.
This behavior is different than a SQL datasource in a unit test for instance, where you simply assign the variable. In general, the API's for adding data to unit tests (Microsoft.VisualStudio.TestTools.UnitTesting) are slightly different than the API's for adding data to a web test Microsoft.VisualStudio.TestTools.WebTesting).

How to get value dynamically added textbox values in MVC 3

I want to get the values of dynamically added Textbox on submit button in MVC 3.
I am storing the values in hidden field and getting using FromCollection. Is there any better approach?
If you name your values something like
MyValues[x] where x is a zero based, continuously increasing integer, you can receive the string values as a list of strings named MyValues.
This trick also works for properties if the main model object, if needed.
You should check some articles about how to bind to collections In ASP mvc, they could give you some ideas.
For example http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
You could do something like this (written very quickly outside of editor, so may have typos/issues):
Make a view model:
public class DynamicTextBoxViewModel
{
public IList<string> DynamicTextBox { get; set; }
public int OtherStuffInViewModel { get; set; }
}
Then in your Get Action:
var model = new YourViewModel
{
DynamicTextBoxList =
new List<DynamicTextBox>
{
new DynamicTextBox
{
TextBoxText = string.Empty,
}
},
OtherStuffInViewModel = xxx,
};
return View(model)
Then in your Post Action:
You would bind everything where you wanted it.
The idea is to move all the data into a ViewModel and pass that around so you gain the benefits of the ViewModel instead of passing around FormCollection - which is sloppier and more error prone.

MVC Model Binding a Complex Type to a Simple Type and Vice Versa

Here's a scenario:
I have an autocomplete plugin (custom) that keeps a hidden field of JSON objects (using a specific struct).
I've created an Html helper that helps me easily bind to a specific custom model (basically, it has a JSON property that is for two-way binding and a property that lets me deserialize the JSON into the appropriate struct):
public class AutoCompleteModel {
public string JSON { get; set; }
public IEnumerable<Person> People {
get {
return new JavaScriptSerializer().Deserialize<Person>(this.JSON);
}
set {
this.JSON = new JavaScriptSerializer().Serialize(value);
}
}
}
This works great and I can model bind using the default binder #Html.Autocomplete(viewModel => viewModel.AutoCompleteModelTest). The HTML helper generates HTML like:
<input type="text" id="AutoCompleteModelTest_ac" name="AutoCompleteModelTest_ac" value="" />
<input type="hidden" id="AutoCompleteModelTest_JSON" name="AutoCompleteModelTest.JSON" value="{JSON}" />
The problem is this is not the best way for consumers. They have to manually set the People property to an array of Person structs. In my data layer, my domain objects probably will not be storing the full struct, only the person's ID (a corporate ID). The autocomplete will take care of looking up the person itself if only given an ID.
The best scenario will be to call it like this:
#Html.Autocomplete(domainObject => domainObject.PersonID) or
#Html.Autocomplete(domainObject => domainObject.ListOfPersonIDs
I would like it to work against the string property AND against the custom AutoCompleteModel. The autocompleter only updates a single hidden field, and that field name is passed back on postback (the value looks like: [{ "Id":"12345", "FullName":"A Name"},{ "Id":"12347", "FullName":"Another Name" }]).
The problem is, of course, that those domain object properties only have an ID or array of IDs, not a full Person struct (so cannot be directly serialized into JSON). In the HTML helper, I can transform those property values into a struct, but I don't know how to transform it back into a simple type on POST. The solution I need would transform an ID into a new Person struct on page load, serializing it into the hidden field. On POST, it would deserialize the generated JSON back into a simple array of IDs.
Is a custom model binder the solution I need? How can I tell it to work both with a custom model AND simple types (because I don't want it applied to EVERY string property, just need it to deal with the values given by the HTML helper).
I figured it out, it's possible!
To clarify, I needed to: transform a string or string array (of IDs) into a JSON structure for my hidden field value, then on post back, deserialize the JSON in the hidden field and transform the struct back into a simple string or string array (of IDs) for my domain object's property.
Step 1: Create a HTML helper
I had done this already, but only for accepting my custom AutoCompleteModel type. I needed one for a string and an Enumerable of string type.
All I did was generate my Person struct(s) from the value of the property and serialize them into JSON for the hidden field the Autocompleter uses (this is an example of the string helper, I also have a nearly identical one for IEnumerable<string>):
public static MvcHtmlString AutoComplete<TModel>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, string>> idProp)
where TModel : class
{
TModel model = htmlHelper.ViewData.Model;
string id = idProp.Compile().Invoke(model);
string propertyName = idProp.GetPropertyName();
Person[] people = new Person[] {
new Person() { ID = id }
};
// Don't name the textbox the same name as the property,
// otherwise the value will be whatever the textbox is,
// if you care.
MvcHtmlString textBox = htmlHelper.TextBox(propertyName + "_ac", string.Empty);
// For me, the JSON is the value I want to postback
MvcHtmlString hidden = htmlHelper.Hidden(propertyName, new JavaScriptSerializer().Serialize(people));
return MvcHtmlString.Create(
"<span class=\"AutoComplete\">" +
textBox.ToHtmlString() +
hidden.ToHtmlString() +
"</span>");
}
Usage: #Html.AutoComplete(model => model.ID)
Step 2: Create a custom model binder
The crux of my issue was that I needed this binder to only apply to certain properties, and they were strings or string arrays.
I was inspired by this article because it used Generics. I decided, hey, we can just ask people what property they want to apply the binder for.
public class AutoCompleteBinder<T> : DefaultModelBinder
where T : class
{
private IEnumerable<string> PropertyNames { get; set; }
public AutoCompleteBinder(params Expression<Func<T, object>>[] idProperties)
{
this.PropertyNames = idProperties.Select(x => x.GetPropertyName());
}
protected override object GetPropertyValue(
ControllerContext controllerContext,
ModelBindingContext bindingContext,
PropertyDescriptor propertyDescriptor,
IModelBinder propertyBinder)
{
var submittedValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (submittedValue != null && this.PropertyNames.Contains(propertyDescriptor.Name))
{
string json = submittedValue.AttemptedValue;
Person[] people = new JavaScriptSerializer().Deserialize<Person[]>(json);
if (people != null && people.Any())
{
string[] IDs = people.Where(x => !string.IsNullOrEmpty(x.ID)).Select(x => x.ID).ToArray();
bool isArray = bindingContext.ModelType != typeof(string) &&
(bindingContext.ModelType == typeof(string[]) ||
bindingContext.ModelType.HasInterface<IEnumerable>());
if (IDs.Count() == 1 && !isArray)
return IDs.First(); // return string
else if (IDs.Count() > 0 && isArray)
return IDs.ToArray(); // return string[]
else
return null;
}
else
{
return null;
}
}
return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
}
}
GetPropertyName() (translate LINQ expression into a string, i.e. m => m.ID = ID) and HasInterface() are just two utility methods I have.
Step 3: Register
Register the binder on your domain objects and their properties in Application_Start:
ModelBinders.Binders.Add(typeof(Employee), new AutoCompleteBinder<Employee>(e => e.ID, e => e.TeamIDs));
It's only a little bit annoying to have to register the binder for specific properties, but it's not the end of the world and provides a nice, smooth experience working with my autocompleter.
Any comments are welcome.

Resources