I have a controller action with a Dictionary argument:
[HttpPost]
[AllowCrossSiteJson]
public ActionResult MyActionMethod(Dictionary<string, string> EnteredValues)
When I try to invoke this method using JSON, the dictionary entries with an # sign in them get removed from the list. For instance, if I invoke the method using this JSON:
{
"EnteredValues": {
"__EVENTTARGET": "",
"__EVENTARGUMENT": "",
"__LASTFOCUS": "",
"ctl00$txtContractQuickSearch": "Contract Search",
"ctl00$txtAdvisorQuickSearch": "Rep Search",
"New Business.#StartDate": "1/1/2013",
"New Business.#EndDate": "10/25/2013",
"New Business.#RegionCode": "All",
"ShowChart": "on",
"txtSearchContractNumber": "Contract Number",
"txtSearchContractFirstName": "Owner First Name",
"txtSearchContractLastName": "Owner Last Name",
"DXScript": "1_42"
}
}
The 3 "New Business" entries get removed because they have an # sign in them. Why is this happening and how do I fix it?
Try to wrap your dictionary entries with an # sign with single quotes.
"'New Business.#StartDate'": "1/1/2013"
Or
"New Business.'#StartDate'": "1/1/2013"
After looking into model binders and dynamic JSON objects, I was able to work around this issue by creating my own Dictionary model binder:
public class DictionaryStringModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
Dictionary<string, string> model = new Dictionary<string, string>();
string contentType = controllerContext.RequestContext.HttpContext.Request.ContentType;
if (contentType != null && contentType.Contains("application/json"))
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
controllerContext.RequestContext.HttpContext.Request.InputStream.Position = 0;
string content = new StreamReader(controllerContext.RequestContext.HttpContext.Request.InputStream).ReadToEnd();
var dynamicContent = Json.Decode(content);
foreach (string property in dynamicContent.GetDynamicMemberNames())
{
if (property == bindingContext.ModelName)
{
foreach (string dictionaryProperty in dynamicContent[property].GetDynamicMemberNames())
{
model.Add(dictionaryProperty, dynamicContent[property][dictionaryProperty]);
}
break;
}
}
}
else
{
model = (Dictionary<string, string>)ModelBinders.Binders.DefaultBinder.BindModel(controllerContext, bindingContext);
}
return model;
}
}
Then inside Globals.asax:Application_Start, I bound this model binder like so:
ModelBinders.Binders[typeof(Dictionary<string, string>)] = new DictionaryStringModelBinder();
My dictionaries are now property being deserialized even if the key has an # in it. Note that this will only work if the dictionary is in the root of both the action arguments (i.e. not inside a class within an action argument) and the JSON.
Related
I have a c# application where I need to return translated keypair value for different views.
For example, these are some of my views:
login
admin account
admin settings
admin employee
admin holiday
and so on.
Then every view call the same method for returning a dictionary of translation strings.
public ActionResult GetTranslations(string viewName)
{
// THIS IS A SAMPLE OF HOW TO GET THE TRANSLATIONS
Dictionary<string, string> translations = new Dictionary<string, string>
{
{ "usernamerequired", HttpContext.GetText("The user name is required","") },
{ "passrequired", HttpContext.GetText("The password is required", "") },
};
string json = JsonConvert.SerializeObject(points, Formatting.Indented);
var response = new JsonResponse
{
data = translations ,
message = "",
num = 0,
success = true,
code = null
};
return Json(response, JsonRequestBehavior.AllowGet);
}
So in order to avoid using "n" amount of Switch statements like:
Dictionary<string, string> translations = null;
switch(viewName)
{
case "login":
// specific translation for login
translations = new Dictionary<string, string>
{
{ "usernamerequired", HttpContext.GetText("The user name is required","") },
{ "passrequired", HttpContext.GetText("The password is required", "") },
};
break;
// HERE OTHER CASES FOR THE OTHER VIEWS
}
Instead I would like to use a cleaner way, I was thinkin on having an interface like:
// Interface
interface ITranslation
{
Dictionary<string, string> GetViewTranslations();
}
// Login translation class
class LoginTranslation: ITranslation
{
public Dictionary<string, string> GetViewTranslations()
{
// here the dictrionary generation code..
}
}
// Admin Settings translation class
class AdminSettingsTranslation: ITranslation
{
public Dictionary<string, string> GetViewTranslations()
{
// here the dictrionary generation code..
}
}
Of maybe there is a better and cleaner way, any advice or clue?
Let's assume that I have a view model like this
public class ExampleVM
{
[Display(Name = "Foo")]
public Nullable<decimal> FooInternal { get; set; }
}
My view looks like this (also a form tag which I omitted in this post)
#model ExampleVM
....
<input asp-for="FooInternal" class="form-control" type="number" />
This results in a rendered text box with FooInternal as id-attribute.
In my scenario, I also have a modal dialog with another form with another view model which shares a property with the same name. I know that the asp-for taghelper renders the id-attribute either a manually from a specified id or infers the id from the property name.
In my backend code, I want to be able to name my properties how I seem fit given the view model context. I don't want to rename my properties to make them globally unique.
I try to avoid two things:
To manually specify the id in the view / the input element. I'd much rather use an autogenerated id that I can set via another attribute in the backend.
Given that I use the view model with [FromBody] in a post, I can't exactly rename the property as it would be with [FromRoute(Name="MyFoo")]. I don't want to map a manually entered id back to my property.
Basically, I'm looking for something like this:
public class ExampleVM
{
[Display(Name = "Foo")]
[HtmlId(Name = "MyUniqueFooName")]
public Nullable<decimal> FooInternal { get; set; }
}
where HtmlId would be an attribute that interacts with the tag-helper for rendering and also for rebinding the view model as parameter from a [HttpPost] method.
Maybe another approach is also valid since avoiding multiple input elements (with the same identifier) in multiple forms on the same page seems like a common situation to me.
According to your description, if you want to achieve your requirement, you should write custom modelbinding and custom input tag helper to achieve your requirement.
Since the asp.net core modelbinding will bind the data according to the post back's form data, you should firstly write the custom input tag helper to render the input name property to use HtmlId value.
Then you should write a custom model binding in your project to bind the model according to the HtmlId attribute.
About how to re-write the custom input tag helper, you could refer to below steps:
Notice: Since the input tag helper has multiple type "file, radio,checkbox and else", you should write all the logic based on the source codes.
According to the input taghelper source codes, you could find the tag helper will call the Generator.GenerateTextBox method to generate the input tag html content.
The Generator.GenerateTextBox has five parameters, the third parameter expression is used to generate the input textbox's for attribute.
Generator.GenerateTextBox(
ViewContext,
modelExplorer,
For.Name,
modelExplorer.Model,
format,
htmlAttributes);
If you want to show the HtmlId value as the name for the for attribute, you should create a custom input taghelper.
You should firstly create a custom attribute:
[System.AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
public class HtmlId : Attribute
{
public string _Id;
public HtmlId(string Id) {
_Id = Id;
}
public string Id
{
get { return _Id; }
}
}
Then you could use var re = ((Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadata)For.ModelExplorer.Metadata).Attributes.PropertyAttributes.Where(x => x.GetType() == typeof(HtmlId)).FirstOrDefault(); to get the htmlid in the input tag helper's GenerateTextBox method.
Details, you could refer to below custom input tag helper codes:
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Rendering;
namespace SecurityRelatedIssue
{
[HtmlTargetElement("input", Attributes = ForAttributeName, TagStructure = TagStructure.WithoutEndTag)]
public class CustomInputTagHelper: InputTagHelper
{
private const string ForAttributeName = "asp-for";
private const string FormatAttributeName = "asp-format";
public override int Order => -10000;
public CustomInputTagHelper(IHtmlGenerator generator)
: base(generator)
{
}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
// Pass through attributes that are also well-known HTML attributes. Must be done prior to any copying
// from a TagBuilder.
if (InputTypeName != null)
{
output.CopyHtmlAttribute("type", context);
}
if (Name != null)
{
output.CopyHtmlAttribute(nameof(Name), context);
}
if (Value != null)
{
output.CopyHtmlAttribute(nameof(Value), context);
}
// Note null or empty For.Name is allowed because TemplateInfo.HtmlFieldPrefix may be sufficient.
// IHtmlGenerator will enforce name requirements.
var metadata = For.Metadata;
var modelExplorer = For.ModelExplorer;
if (metadata == null)
{
throw new InvalidOperationException();
}
string inputType;
string inputTypeHint;
if (string.IsNullOrEmpty(InputTypeName))
{
// Note GetInputType never returns null.
inputType = GetInputType(modelExplorer, out inputTypeHint);
}
else
{
inputType = InputTypeName.ToLowerInvariant();
inputTypeHint = null;
}
// inputType may be more specific than default the generator chooses below.
if (!output.Attributes.ContainsName("type"))
{
output.Attributes.SetAttribute("type", inputType);
}
// Ensure Generator does not throw due to empty "fullName" if user provided a name attribute.
IDictionary<string, object> htmlAttributes = null;
if (string.IsNullOrEmpty(For.Name) &&
string.IsNullOrEmpty(ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix) &&
!string.IsNullOrEmpty(Name))
{
htmlAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
{
{ "name", Name },
};
}
TagBuilder tagBuilder;
switch (inputType)
{
//case "hidden":
// tagBuilder = GenerateHidden(modelExplorer, htmlAttributes);
// break;
//case "checkbox":
// tagBuilder = GenerateCheckBox(modelExplorer, output, htmlAttributes);
// break;
//case "password":
// tagBuilder = Generator.GeneratePassword(
// ViewContext,
// modelExplorer,
// For.Name,
// value: null,
// htmlAttributes: htmlAttributes);
// break;
//case "radio":
// tagBuilder = GenerateRadio(modelExplorer, htmlAttributes);
// break;
default:
tagBuilder = GenerateTextBox(modelExplorer, inputTypeHint, inputType, htmlAttributes);
break;
}
if (tagBuilder != null)
{
// This TagBuilder contains the one <input/> element of interest.
output.MergeAttributes(tagBuilder);
if (tagBuilder.HasInnerHtml)
{
// Since this is not the "checkbox" special-case, no guarantee that output is a self-closing
// element. A later tag helper targeting this element may change output.TagMode.
output.Content.AppendHtml(tagBuilder.InnerHtml);
}
}
}
private TagBuilder GenerateTextBox(
ModelExplorer modelExplorer,
string inputTypeHint,
string inputType,
IDictionary<string, object> htmlAttributes)
{
var format = Format;
if (string.IsNullOrEmpty(format))
{
if (!modelExplorer.Metadata.HasNonDefaultEditFormat &&
string.Equals("week", inputType, StringComparison.OrdinalIgnoreCase) &&
(modelExplorer.Model is DateTime || modelExplorer.Model is DateTimeOffset))
{
// modelExplorer = modelExplorer.GetExplorerForModel(FormatWeekHelper.GetFormattedWeek(modelExplorer));
}
else
{
//format = GetFormat(modelExplorer, inputTypeHint, inputType);
}
}
if (htmlAttributes == null)
{
htmlAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
}
htmlAttributes["type"] = inputType;
if (string.Equals(inputType, "file"))
{
htmlAttributes["multiple"] = "multiple";
}
var re = ((Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadata)For.ModelExplorer.Metadata).Attributes.PropertyAttributes.Where(x => x.GetType() == typeof(HtmlId)).FirstOrDefault();
return Generator.GenerateTextBox(
ViewContext,
modelExplorer,
((HtmlId)re).Id,
modelExplorer.Model,
format,
htmlAttributes);
}
}
}
Improt this taghelper in _ViewImports.cshtml
#addTagHelper *,[yournamespace]
Model exmaple:
[Display(Name = "Foo")]
[HtmlId("test")]
public string str { get; set; }
Result:
Then you could write a custom model binding for the model to bind the data according to the htmlid. About how to use custom model binding, you could refer to this article.
Imagine an object defined like :
public class MyViewModel{
public List<string> MyList { get; set; }
}
In my view, i have this Action link :
#Ajax.ActionLink("<", "Index", new MyViewModel() { MyList = new List<string>() {"foo", "bar"}}, new AjaxOptions())
The html result of the ActionLink will be :
<a class="btn btn-default" data-ajax="true" href="/Index?MyList=System.Collections.Generic.List%601%5BSystem.String%5D"><</a>
My question is, how get this result rather :
<a class="btn btn-default" data-ajax="true" href="/Index?MyList=foo&MyList=bar"><</a>
You can try string.Join. Something like this
#Ajax.ActionLink(
"Your text", -- <
"ActionName", -- Index
new
{
MyList =string.Join(",", new List<string>() {"foo", "bar"}),
otherPropertiesIfyouwant = YourValue
}, -- rounteValues
new AjaxOptions { UpdateTargetId = "..." }, -- Your Ajax option --optional
new { #id = "back" } -- Your html attribute - optional
)
You cannot use #Html.ActionLink() to generate route values for a collection. Internally the method (and all the MVC methods that generate urls) uses the .ToString() method of the property to generate the route/query string value (hence your MyList=System.Collections.Generic.List%601%5BSystem.String%5D" result).
The method does not perform recursion on complex properties or collections for good reason - apart from the ugly query string, you could easily exceed the query string limit and throw an exception.
Its not clear why you want to do this (the normal way is to pass an the ID of the object, and then get the data again in the GET method based on the ID), but you can so this by creating a RouteValueDictionary with indexed property names, and use it in your#Ajax.ActionLink() method.
In the view
#{
var rvd = new RouteValueDictionary();
rvd.Add("MyList[0]", "foo");
rvd.Add("MyList[1]", "bar");
}
#Ajax.ActionLink("<", "Index", rvd, new AjaxOptions())
Which will make a GET to
public ActionResult Index(MyViewModel model)
However you must also make MyList a property (the DefaultModelBinder does not bind fields)
public class MyViewModel{
public List<string> MyList { get; set; } // add getter/setter
}
and then the value of model.MyList in the POST method will be ["foo", "bar"].
With Stephen's anwser, i have develop a helper extension method to do this.
Be careful of the URL query string limit : if the collection has too many values, the URL can be greater than 255 characters and throw an exception.
public static class AjaxHelperExtensions
{
public static MvcHtmlString ActionLinkUsingCollection(this AjaxHelper ajaxHelper, string linkText, string actionName, object model, AjaxOptions ajaxOptions, IDictionary<string, object> htmlAttributes)
{
var rv = new RouteValueDictionary();
foreach (var property in model.GetType().GetProperties())
{
if (typeof(ICollection).IsAssignableFrom(property.PropertyType))
{
var s = ((IEnumerable<object>)property.GetValue(model));
if (s != null && s.Any())
{
var values = s.Select(p => p.ToString()).Where(p => !string.IsNullOrEmpty(p)).ToList();
for (var i = 0; i < values.Count(); i++)
rv.Add(string.Concat(property.Name, "[", i, "]"), values[i]);
}
}
else
{
var value = property.GetGetMethod().Invoke(model, null) == null ? "" : property.GetGetMethod().Invoke(model, null).ToString();
if (!string.IsNullOrEmpty(value))
rv.Add(property.Name, value);
}
}
return AjaxExtensions.ActionLink(ajaxHelper, linkText, actionName, rv, ajaxOptions, htmlAttributes);
}
}
I send post request and get in response body form data:
0[family]=Marco&0[name]=Polo&0[age]=66&1[family]=Family&0[name]=Name&0[age]=22
var formData = "0[family]=Marco&0[name]=Polo&0[age]=66&1[family]=Family&0[name]=Name&0[age]=22";
var data = new Dictionary<string, string>();
var preData = HttpUtility.ParseQueryString(formData);
foreach (string key in preData.AllKeys)
{
if (key != null)
{
data.Add(Replace(key), preData[key]);
}
}
I have model:
public class User {
public string Family {get;set;}
public int Age {get;set;}
}
For bind I use DefaultModelBinder:
private static bool TryUpdateModel(User user, IDictionary<string, string> formdata, ModelStateDictionary modelState) where TModel : class
{
var binder = new DefaultModelBinder();
var valueProvider = new DictionaryValueProvider<string>(formdata, CultureInfo.InvariantCulture);
var bindingContext = new ModelBindingContext
{
ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => user, typeof(User)),
ModelState = modelState,
PropertyFilter = propertyName => true,
ValueProvider = valueProvider
};
var ctx = new ControllerContext();
binder.BindModel(ctx, bindingContext);
return modelState.IsValid;
}
I want to know that I have data in responce "0[name]=Polo" which didn't bind to model User. Property "Name" don't exist in model User.
I want know if in response was more data then we can bind.
How I can do it?
You still need to compare the Model to the form data in each case so you could try something like the below:
public bool HasAdditionalVals<TModel>(TModel model, IDictionary<string, string> formData)
{
var propsNameList = new List<string>();
var propsList = typeof(TModel).GetProperties().ToList();
propsList.ForEach(p => propsNameList.Add(p.Name.ToLower()));
var keysList = formdata.Keys.ToList()
var additionalProps = keysList.Except(propsNameList);
return additionalProps.Count() > 0;
}
You could then call this within your 'TryUpdateModel' or wherever you need to check if the form data has more properties than the model you are trying to bind to. Just to note though that this is reliant on the form data keys being in lower case. If not you will have to ensure that they are before calling 'keysList.Except(propsNameList)'.
I have this (simplified) class:
public class StarBuildParams
{
public int BaseNo { get; set; }
public int Width { get; set; }
}
And I have to transform instances of it to a querystring like this:
"BaseNo=5&Width=100"
Additionally I have to transform such a querystring back in an object of that class.
I know that this is pretty much what a modelbinder does, but I don't have the controller context in my situation (some deep buried class running in a thread).
So, is there a simple way to convert a object in a query string and back without having a controller context?
It would be great to use the modelbinding but I don't know how.
A solution with Newtonsoft Json serializer and linq:
string responseString = "BaseNo=5&Width=100";
var dict = HttpUtility.ParseQueryString(responseString);
string json = JsonConvert.SerializeObject(dict.Cast<string>().ToDictionary(k => k, v => dict[v]));
StarBuildParams respObj = JsonConvert.DeserializeObject<StarBuildParams>(json);
You can use reflection, something like this:
public T GetFromQueryString<T>() where T : new(){
var obj = new T();
var properties = typeof(T).GetProperties();
foreach(var property in properties){
var valueAsString = HttpContext.Current.Request.QueryString[property.PropertyName];
var value = Parse( valueAsString, property.PropertyType);
if(value == null)
continue;
property.SetValue(obj, value, null);
}
return obj;
}
You'll need to implement the Parse method, just using int.Parse, decimal.Parse, DateTime.Parse, etc.
Use this Parse method with the ivowiblo's solution (accepted answer):
public object Parse(string valueToConvert, Type dataType)
{
TypeConverter obj = TypeDescriptor.GetConverter(dataType);
object value = obj.ConvertFromString(null, CultureInfo.InvariantCulture, valueToConvert);
return value;
}
You can set the properties of this object in its constructor by retrieving the relevant values from the querystring
public StarBuildParams()
{
this.BaseNo = Int32.Parse(Request.QueryString["BaseNo"].ToString());
this.Width = Int32.Parse(Request.QueryString["Width"].ToString());
}
and you can ensure that the object is converted to the correct querystring format by overriding the ToString method.
public override string ToString()
{
return String.Format("BaseNo={0}&Width={1}", this.BaseNo, this.Width);
}
You'll still need to construct and call ToString in the appropriate places, but this should help.
You can just use .NET's HttpUtility.ParseQueryString() method:
HttpUtility.ParseQueryString("a=b&c=d") produces a NameValueCollection as such:
[0] Key = "a", Value = "b"
[1] Key = "c", Value = "d"
This should work so long as none of the properties match any other route parameters like controller, action, id, etc.
new RouteValueDictionary(Model)
http://msdn.microsoft.com/en-us/library/cc680272.aspx
Initializes a new instance of the RouteValueDictionary class and adds
values that are based on properties from the specified object.
To parse back from the query string you can use the model class as an action parameter and let the ModelBinder do it's job.
Serialize query string and deserialize to your class object
JObject json;
Request.RequestUri.TryReadQueryAsJson(out json);
string sjson = JsonConvert.SerializeObject(json);
StarBuildParams query = JsonConvert.DeserializeObject<StarBuildParams>(sjson);
Building off of Ivo and Anupam Singh's great solutions above, here is the code that I used to turn this into a base class for POST requests (in the event that you may only have the raw query string like in a Web API setup). This code works for lists of objects, but could easily be modified to parse a single object.
public class PostOBjectBase
{
/// <summary>
/// Returns a List of List<string> - one for each object that is going to be parsed.
/// </summary>
/// <param name="entryListString">Raw query string</param>
/// <param name="firstPropertyNameOfObjectToParseTo">The first property name of the object that is sent in the list (unless otherwise specified). Used as a key to start a new object string list. Ex: "id", etc.</param>
/// <returns></returns>
public List<List<string>> GetQueryObjectsAsStringLists(string entryListString, string firstPropertyNameOfObjectToParseTo = null)
{
// Decode the query string (if necessary)
string raw = System.Net.WebUtility.UrlDecode(entryListString);
// Split the raw query string into it's data types and values
string[] entriesRaw = raw.Split('&');
// Set the first property name if it is not provided
if (firstPropertyNameOfObjectToParseTo == null)
firstPropertyNameOfObjectToParseTo = entriesRaw[0].Split("=").First();
// Create a list from the raw query array (more easily manipulable) for me at least
List<string> rawList = new List<string>(entriesRaw);
// Initialize List of string lists to return - one list = one object
List<List<string>> entriesList = new List<List<string>>();
// Initialize List for current item to be added to in foreach loop
bool isFirstItem = false;
List<string> currentItem = new List<string>();
// Iterate through each item keying off of the firstPropertyName of the object we will ultimately parse to
foreach (string entry in rawList)
{
if (entry.Contains(firstPropertyNameOfObjectToParseTo + "="))
{
// The first item needs to be noted in the beginning and not added to the list since it is not complete
if (isFirstItem == false)
{
isFirstItem = true;
}
// Finished getting the first object - we're on the next ones in the list
else
{
entriesList.Add(currentItem);
currentItem = new List<string>();
}
}
currentItem.Add(entry);
}
// Add the last current item since we could not in the foreach loop
entriesList.Add(currentItem);
return entriesList;
}
public T GetFromQueryString<T>(List<string> queryObject) where T : new()
{
var obj = new T();
var properties = typeof(T).GetProperties();
foreach (string entry in queryObject)
{
string[] entryData = entry.Split("=");
foreach (var property in properties)
{
if (entryData[0].Contains(property.Name))
{
var value = Parse(entryData[1], property.PropertyType);
if (value == null)
continue;
property.SetValue(obj, value, null);
}
}
}
return obj;
}
public object Parse(string valueToConvert, Type dataType)
{
if (valueToConvert == "undefined" || valueToConvert == "null")
valueToConvert = null;
TypeConverter obj = TypeDescriptor.GetConverter(dataType);
object value = obj.ConvertFromString(null, CultureInfo.InvariantCulture, valueToConvert);
return value;
}
}
Then you can inherit from this class in wrapper classes for POST requests and parse to whichever objects you need. In this case, the code parses a list of objects passed as a query string to a list of wrapper class objects.
For example:
public class SampleWrapperClass : PostOBjectBase
{
public string rawQueryString { get; set; }
public List<ObjectToParseTo> entryList
{
get
{
List<List<string>> entriesList = GetQueryObjectsAsStringLists(rawQueryString);
List<ObjectToParseTo> entriesFormatted = new List<ObjectToParseTo>();
foreach (List<string> currentObject in entriesList)
{
ObjectToParseToentryPost = GetFromQueryString<ObjectToParseTo>(currentObject);
entriesFormatted.Add(entryPost);
}
return entriesFormatted;
}
}
}