how to append nested object to FormData with .net core and angular 8 - angular8

I am developing an application using angular as frontend and API in .net core.
My API model is as below:
class Tag
{
public int ID {get;set;}
public string Name {get;set;}
public string Description {get;set;}
}
And the Post class is as below
class Post
{
public int ID {get;set;}
..... //other properties
public IEnumerable<Tag> Tags {get;set;}
}
The same class I am having in angular as well.
Here I have to upload image and other properties with tags as well.
const formData = new FormData();
if(blogRequest.imageContent){
formData.append('file', postRequest.imageContent, postRequest.imageContent.name);
}
formData.append("Title",postRequest.title);
.... // appended other data as well
///formData.append("Tags",tags); <-- how do I append tag object here. JSON.Stringify(tags) is not working as it is not assigning in the api model. I have to manually deserialize to object which I don't want.
I have tried below
var tags:Tag[]=[];
var t1 = new Tag();
t1.Name="some";
t1.ID=0;
t1.Description="desc";
var t2 = new Tag();
t2.Name="some";
t2.ID=0;
t2.Description="desc";
tags[0] =t1;
tags[1] = t2;
formData.append("Tags[]","{Name:some}");
formData.append("Tags[]","{Name:something}");
formData.append("Tags[].Name","some");
formData.append("Tags[].Name","something");
Non of them worked. The tags is passing as array when I debug and watch the Request.Form but it is not assigning to the object. The Tags count is always 0.
I can provide more info if needed. thanks in advance.

Related

ASP.NET Core 6 Write value to Page without iteration?

I am trying to write a specific value to a page in ASP.NET Core 6. I found multiple solutions with iterators but I am not able to write a single value from non-iteratable models / instances (no enumerators & lists) to a page.
public class UserViewModel
{
public string Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
}
This models purpose is to get filled with values from the Identity Framework.
public UserViewModel umodel { get; set; }
Said model gets instanced, filled without any problems - it holds values (checked via console) in page.cshtml.cs:
var user = await _userManager.FindByIdAsync(id);
UserViewModel UserModel = new UserViewModel();
UserModel.UserName = user.UserName;
UserModel.Email = user.Email;
UserModel.Id = user.Id;
Console.WriteLine(UserModel.UserName);
Console.WriteLine(UserModel.Id);
Console.WriteLine(UserModel.Email);
If I try to access it on the corresponding page (page.cshtml) I can only access its name without any problems:
#Html.DisplayNameFor(model => model.umodel.Email)
When I want to access its content there is no value on the page.
#Html.DisplayFor(model => model.umodel.Email)
How can I access the values in this model on a razor page? All the solutions I found based on some kind of iterator and therefore models that had some kind of enumerator or where instanced and filled as a list.
From the code you posted, you aren't populating the page's UserViewModel property. You instantiated a different UserViewModel instance. You wrote the values of that to the Console, but the actual model property (umodel) has not been populated.
Try this in the OnGet method:
var user = await _userManager.FindByIdAsync(id);
umodel.UserName = user.UserName;
umodel.Email = user.Email;
umodel.Id = user.Id;
When rendering property values, you don't need the DisplayFor helper (unless you are using display templates). You just need to prefix the property with #:
#Model.umodel.UserName
I figured it out. There hast to be an instance of the model / class but in a specific way and naming. See following example:
Model:
public class IdentityUserModel
{
public string Id { get; set; }
public string ?UserName { get; set; }
public string ?Email { get; set; }
}
Reference to model in the Main class of the Page (page.cshtml.cs):
public IdentityUserModel IUserModel { get; set; }
Then the important part in the OnGet/OnGetAsync function(?) (page.cshtml.cs):
IUserModel = new(); // <-- instance
var user = [whatever...]
IUserModel.UserName = user.UserName;
IUserModel.Email = user.Email;
IUserModel.Id = user.Id;
Then to write on the page.cshtml:
#Model.IUserModel.Id
My understanding is that there has to be an instance of the class in die page context with exactly the same name (therefore = new() without instance name). I may have been blind but reading throug microsofts learn pages again this is was not clear at all to me.
Thanks to Mike Brind for sending me in the right direction with his input.

FromForm attribute for binding doesn't work on .NET CORE API

I'm trying to also support formdata in my controllers but it seems to be not working.
This is my controller action;
[HttpPost]
[Route("create_foo_from_form")]
public ActionResult<Foo> GetFooFORM([FromForm] Bar requestForm)
{
var abc = ExecuteAction(() =>
{
return _fooService.AddFoo(requestForm);
});
return abc.Result;
}
My Bar Object is;
public class Bar
{
...
public string BarNo { get; set; }
...
}
But whenever I try to send FormData or x-www-form-urlencoded data to the api using Postman with the value BarNo=123456 the controller action doesn't catch on that. And the requestForm object's BarNo attribute always is null.
Also [FromBody] works just fine if I send Json Raw Data from Postman.
Picture:
Did you try like this:
Result:

Vuejs access / expose object from within ASP.NET Core app

Working on a project in ASP.NET Core MVC with VueJS as my frontend. I am looking for a solution to expose server objects to my Vuejs frontend to store it in my Vuex store so I can access them anywhere in my app.
For example, the build version / app version, appname, company name, ...
Some of these are located in the appsettings.json, others are in the .csproj file which I can read using a service.
I want to expose a json object during startup which contains these properties.
What do I have so far:
I have a root AppConfig class which contains all the properties.
AppConfig.cs
public class AppConfig : IValidatableConfig
{
public string AppName { get; set; }
public string ShortName { get; set; }
public int CurrentYear => DateTime.Now.Year;
/// Company Section
public CompanySettings CompanySettings { get; set; }
/// <summary>
/// Validate AppConfig
/// </summary>
/// <returns></returns>
public bool IsValid() => !string.IsNullOrEmpty(AppName) &&
!string.IsNullOrEmpty(ShortName) && CompanySettings != null &&
!string.IsNullOrEmpty(CompanySettings.Name) && !string.IsNullOrEmpty(CompanySettings.Url);
}
Startup.cs
// Bind IConfiguration AppConfig section to strongly typed object
services.Configure<AppConfig>(Configuration.GetSection("AppConfig"));
// Explicitly register the AppConfig object by delegating to the IOptions object
services.AddSingleton(resolver => {
var config = resolver.GetRequiredService<IOptions<AppConfig>>().Value;
if (config.IsValid()) return config;
// We have found issues with the appsettings config, throw exception to notify!
throw new InvalidConfigurationException(typeof(AppConfig));
});
Possible solution but don't like it this way:
Add props to my view root container to expose every property and then store them in my vuex store.
Don't like this because when a new property gets added I need to change a lot of files to make it work.
So I would like to have a solution which parse the AppConfig during startup to a json object and then get it into my Vuejs container.
Other solution
I could use a .env file in my vuejs to store these variables like this:
VUE_APP_ROOT_API = https://localhost:44320/api
VUE_APP_NAME_FOOTER = My Custom APP
VUE_APP_NAME_SHORT = My App
VUE_APP_COMPANY_NAME = Company
VUE_APP_COMPANY_URL = https://test.be
VUE_APP_YEAR = 2019
VUE_APP_VERSION = 0.0.1-local
But how can I dynamically update my version coming from my .csproj file?
Solved it by writing an extension on the HtmlHelper which renders a script tag holding server variables:
public static IHtmlContent RenderServerVariablesScript(this IHtmlHelper html)
{
var str = #"<script type=""text/javascript"">
var base = {};
base.sys = {};
base.sys.serverVariables = {""version"": ""0.0.1-local""};
window.base = base;</script>";
return html.Raw(str);
}
Then in my _layout I use:
#Html.RenderServerVariablesScript()
For this to work I needed to import my namespace in the _ViewImports file.

Restsharp - Exception due to XElement property

I need to make a REST request and pass an object which has a property of XElement type.
The object:
public class Test
{
public string Property1 {get;set;}
public XElement PropertyXml {get;set;}
}
The code:
var testObj = new Test();
testObj.Property1 = "value";
testObj.PropertyXml = new XElement("test");
var level1 = new XElement("level1", "value111");
testObj.PropertyXml.Add(level1);
var client = new RestClient();
client.BaseUrl = new Uri(string.Format(_url));
var rRequest = new RestRequest(_address, Method.POST);
rRequest.RequestFormat = DataFormat.Json;
rRequest.AddBody(testObj);
var response = client.Execute(rRequest);
I get a 'System.StackOverflowException' at the line with AddBody call.
PS I can pass a Test object using HttpClient (I use the PostAsJsonAsync method) instead of Restsharp.
Any ideas would be appreciated ..
RestSharp has no inherent knowledge of XElement, and AddBody will attempt to serialize it like it would any other POCO type - by traversing its properties. You can see this process getting stuck in an infinite cycle quite easily:
testObj.FirstNode.Parent.FirstNode.Parent....
Your best bet is to change the type of your PropertyXml property to a simple POCO type that the XML structure can easily map to. Something like:
public class PropertyStructure
{
public string level1 {get;set;}
}
public class Test
{
public string Property1 {get; set;}
public PropertyStructure PropertyXml {get; set;}
}

WebApi method is unable to bind to model

Basically I'm trying to create a method in my webapi controller:
The method looks like this(the method body is relevant):
[HttpPost]
public HttpResponseMessage CpaLead([FromBody]CpaLeadVM model)
{
Here's the class declaration of the object being passed:
public class CpaLeadVM
{
public string UserIp = "";
public string UserCountry = "";
public double Earn = 0.0;
public string SurveyType = "";
}
The thing is; when I send a post request to the method, the model is always null.
The post request has the following data:
UserIp=hello
Earn=44.4
UserCountry=denmark
SurveyType=free
Shouldn't it be able to bind to the model or am I missing something here?
The problem is the "properties" you are trying to bind to are fields and not actual properties. The model binders and formatters in Web Api doesn't look at fields. If you change your model to:
public class CpaLeadVM
{
public CpaLeadVm()
{
UserIp = "";
UserCountry = "";
Earn = 0.0;
SurveyType = "";
}
public string UserIp {get;set;}
public string UserCountry {get;set;}
public double Earn {get;set;}
public string SurveyType {get;set;}
}
Your binding will work. As a side note, the [FromBody] attribute on your action is redundant since non-primitive values are bound from the request body by default.
As you may know, you can only get a single value from the body, which must be sent as "=value". See this article for more info
http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/
I'm not sure, but I think you could create your own model binder, which parses the body into your class. Another approach is to use JSON. Read more about that here
ASP.NET MVC 4 Post FromBody Not Binding From JSON