jQuery passing params to MVC Controller. Why are my params empty? - c#

I'm converting a Web Forms app to MVC.
I have a js method that calls a Controller action method (below)
function GetUsers(pageNum) {
var sortTh = $('thead .sort', document.getElementById('usersTable'));
var sortCol = sortTh.find('a').attr('rel');
// { } is declarative shorthand for new Object().
var userRequest = {};
userRequest.pageNum = pageNum;
userRequest.pageSize = 10; //records per page
userRequest.sortType = (sortTh.hasClass('ascending')) ? 'ascending' : 'descending';
userRequest.sortColumn = sortCol;
//alert(userRequest.sortType + " - " + sortCol);
// Create a data transfer object (DTO) with the proper structure.
var DTO = { 'userRequest': userRequest };
//Ajax
var urlMethod = "/Users/GetUsers"; //"../WebServices/ws_Users.asmx/GetUsers";
var jsonData = JSON.stringify(DTO);
SendAjax(urlMethod, jsonData, ReturnGetUsers, 'get');
}
This code works, you can even see the Post in Firebug.
{"userRequest":"pageNum":1,"pageSize":10,"sortType":"descending","sortColumn":"LastLoginDate"}}
[HttpPost]
public ActionResult GetUsers(UsersModels.GetUserRequest userRequest)
{
//Talk to Web Service
var wsUsers = new WS_Users();
var userList = wsUsers.GetUsers(userRequest);
return Json(userList);
}
I set a breakpoint in the above and all my parameters are empty? WHY oh why?
Here's the model:
public class GetUserRequest
{
public int pageNum;
public int pageSize;
public string sortType;
public string sortColumn;
}
Help!

I'm not sure but I wonder if the members of GetUserRequest need to be public properties rather than public fields?

SendAjax(urlMethod, jsonData, ReturnGetUsers, 'get');
I don't know what goes on in that SendAjax code but that "get" looks like it should be a "post" to me

your GetUserRequest model should be like this
public class GetUserRequest {
public int pageNum {get;set;}
public int pageSize {get;set;}
public string sortType {get;set;}
public string sortColumn{ get;set;}
}

Related

Upload file in angular / web API

I created a function that add a new user with Angular/WebAPI , so in angular i send the object like this :
AddUser(person : person):Observable<person>
{
return this.http.post<person>(this.baseUrl,person);
}
and in WebAPI i got the data :
[HttpPost]
public async Task<ActionResult<Person>> PostPerson(Person person)
{
Now I want to add a picture of each user, and i don't know how it's gonna be the objet in angular, should i add a property imageProfile as File which i'm not sure if it's possible , or it should be a string of the uploaded file.
export class person {
idPerson:number=0;
fname : string ="" ;
lname : string ="";
password : string ="";
idCategory? :number;
nameCategory:string="";
imageProfile :
}
That's very good info from Codemaze, as always. The remark from Lavstsen is not correct, there's no need for a separate call.
For example, you could have a form linked to the structure of the person-type:
initializeForm() {
this.personForm = this.form.group({
fname: [''],
})
}
In your onSubmit-method, you seize the date from your form and put in a dto, in this example through a getPersonDto-method
private getPersonDto(): PersonDto {
let dto = new PersonDto();
dto.fname = this.imageForm.controls.fname.value;
return dto;
}
and next you can solve it like this:
const formData = new FormData();
formData.append('Imagefile', this.selectedFile, this.selectedFile.name);
formData.append('fname', personDto.fname); // needs to be strings => toString()
this.personApiClient.uploadImageFile(this.personId, formData)
.subscribe((res: any) => {
this.uploadOrDeleteResults = res;
this.showToastrMessageSuccess("PAGES.COMMON.TOASTR.TITLE.SUCCESSFULCREATE", "PAGES.COMMON.TOASTR.MESSAGE.SUCCESSFULCREATE");
},
(error) => {
this.crudHasErrors = true;
this.errorHttpErrorResponse = error;
this.errors = this.errorHttpErrorResponse.error;
},
you don't need the dto-step as such, but if you structurally always use dto's in your application, it would make more sense
Take care and good luck
I have another workaround but this will only work for very small files where you don't need upload percentage to show on UI.
I have my controller like this:
[HttpPost("/api/sign-up")]
public void SaveUser([FromForm] UserModel info)
{
_logger.LogDebug(null, "Hello", info); // Just to see contents of info object in debugger
}
and make your model like this:
public class UserModel
{
[FromForm(Name = "avatar")]
public IFormFile Avatar { get; set; }
[FromForm(Name = "email")]
public string Email { get; set; }
}

Best way to append query string parameter to URL from object

I have query string class.
public class PagingModel
{
public int PageNumber { get; set; } = 1;
public string Filter { get; set; } = "text";
}
string url = "Menu/GetMenus";
I have to generate the URI with a query string based on an object in ASP.NET Core 5 preview. Is there any built in query helper?.
Required output:
/Menu/GetMenus?PageNumber=3&Filter=text
MVC Controller:
public async Task<IActionResult> index_partial([FromQuery] PagingModel paging)
{
var data = await _apiService.GetMenusAsync(paging);
return PartialView("_IndexPartial", data);
}
Service:
public async Task<PagedList<MenuModel>> GetMenusAsync(PagingModel paging)
{
string Requiredurl = "Menu/GetMenus?page="+ paging.PageNumber;
}
I got this extension method.. No need to generate query string manually.Only class object we need to pass. i thought some one else can use the same thing ...
public static string AppendObjectToQueryString(string uri, object requestObject)
{
var type = requestObject.GetType();
var data = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToDictionary
(
p => p.Name,
p => p.GetValue(requestObject)
);
foreach (var d in data)
{
if (d.Value == null)
{
continue;
}
if ((d.Value as string == null) && d.Value is IEnumerable enumerable)
{
foreach (var value in enumerable)
{
uri = QueryHelpers.AddQueryString(uri, d.Key, value.ToString());
}
}
else
{
uri = QueryHelpers.AddQueryString(uri, d.Key, d.Value.ToString());
}
}
return uri;
}
Ex: In my case i called this way.
string uri = "Menu/GetMenus";
string full_uri = QueryStringExtension.AppendObjectToQueryString(uri, paging);
With a Query String this simple I would just do
PagingModel qsData = new PagingModel();
//set qsData properties as needed
string urlWithQueryString = $"/Menu/GetMenus?{nameof(PagingModel.PageNumber)}={qsData.PageNumber}&nameof(PagingModel.Filter)}={qsData.Filter}";
However more standard is to do something like
string urlWithQueryString = this.Url.Action("GetMenus", "Menu", new PagingModel { PageNumber = 3, Filter = "text" }, this.Request.Url.Scheme);
But best solution depends on your specific case - can you add your action method definition for GetMenus ?
Update for your additional code :
Seeing as looks like you want to generate the url inside the service I would simply do this :
public async Task<PagedList<MenuModel>> GetMenusAsync(PagingModel paging)
{
string Requiredurl = $"/Menu/GetMenus?{nameof(PagingModel.PageNumber)}={paging.PageNumber}&nameof(PagingModel.Filter)}={paging.Filter}";
}

Get Relative Path from Route Name

When a path is named...
[Route("api/[controller]/{id}/Existing", Name = "ExistingOrdersLink")]
public class OrdersController : Controller {...}
...it is easy to create an absolute path using its name:
var address = Url.Link("ExistingOrdersLink", new { id = 22 });
However, I need the ability to generate a relative path from a Route name. So I write code like this:
//Is there a built-in mechanism for this?
string partial = new Uri(Url.Link("ExistingOrdersLink", new { id = id })).PathAndQuery;
The above works but, in ASP.NET Core, is there a more direct way to get the same result?
Context
Why do I need this? Some of the controllers I make are actually generic:
[Route("api/Subscribers/{id}/[controller]", "SubscriberLink")]
[Route("api/Organization/{id}/[controller]", "OrganizationLink")]
public class OrdersController<T> : Controller where T : IOrder
{
private ICommand<Order<T>> createOrder;
protected OrdersController(ICommand<Order<T>> createOrder)
{
this.createOrder = createOrder;
}
[HttpPost("{otype}")]
public async Task<IActionResult> Create(
Guid id,
[FromBody] Order<T> order)
{
order.CustomerOrderId = Guid.NewGuid();
createOrder.Handle(order);
string[] segs = Request.Path.Value.Split(new char[] { '/' },StringSplitOptions.RemoveEmptyEntries);
//This will become either "SubscriberLink" or "OrganizationLink"
string route = $"{segs[1]}Link";
//Is there a built-in mechanism for this?
string partial = new Uri(Url.Link(route, new { id = id })).PathAndQuery;
partial = $"{partial}/{order.CustomerOrderId}";
CreatedResult reply = Created(partial, null);
return reply;
}
}
I think you are looking for Url.RouteUrl
Example:
Url.RouteUrl("ExistingOrdersLink", new { id = 22});

RestSharp (C#) - Deserialize JSON Objects to NULL

I'm trying to understand REST by utilizing RestSharp in my application.
Here is a bit of JSON that my client is returning:
{
"result" : {
"object_type" : "session",
"user_id" : "FEE3CBD4-5D35-11E3-A42A-606A40E381E5",
"object_name" : "Session",
"id" : "2F2968B6-5D37-11E3-89F4-5D6A40E381E5"
}
}
Here is my class object:
public class TGCResult : IDeserializer
{
public string object_type {get; set;}
public string user_id { get; set; }
public string object_name { get; set; }
public string id { get; set; }
public TGCResult()
{
}
public override string ToString()
{
return "object_type = " + object_type + "\nuser_id = " + user_id + "\nobject_name = " + object_name + "\nid = " + id;
}
}
And here is the code in which I am retrieving the JSON and attempting to deserialize:
var client = new RestClient("https://www.xxxxxxxxx.com");
var request = new RestRequest("/api/session", Method.POST);
request.AddParameter("username", "JSventoraGD");
request.AddParameter("password", "xxxxxxxxxxxxxxxx");
request.AddParameter("api_key_id", "xxxxxxxxxxxxxxxxxxx");
request.RequestFormat = DataFormat.Json;
var asyncHandle = client.ExecuteAsync<TGCResult>(request, response =>
{
TxtTest.Text = response.Data.ToString();
});
asyncHandle.Abort();
When doing this, I can see the data is returned to my application correctly, but the Data in my response always has NULL values. Any ideas on why this might be happening? Am I supposed to manually deserialize the JSON given the content? The samples I've seen online have a very similar setup to mine, I'm lost... any help is greatly appreciated!
var asyncHandle=client.ExecuteAsync(request,response=>{
String res=response.Content;
T obj = Newtonsoft.Json.JsonConvert.DeserializeObject<T>(res);
});
Try adding
request.RootElement = "result";
I have just spent a couple of hours trying to get a simple GET request to parse anything but null, setting RootElement helped me. Bit surprised i needed it since you set your type class several other places in the code.
Try using it like this
var asyncHandle = client.ExecuteAsync(request, response =>
{
var json = response.Content;
// deserialize to TGCResult
});
This works fine for me
It seems you need to have another class as your Data type.
public class TGCResultContainer
{
public TGCResult result { get; set; }
}
Also, your TGCResult class does not need to implement IDeserializer.

Custom generic DTO Assembler

I'm trying to create a method which can be used like this:
Assembler.CreateTransfer(i);
i is an item inside a dynamic collection.
i is a domain object.
CreateTransfer() should return an instance of i type + Transfer (if my domain object is User, then it should return an instance of UserTransfer.
As for my models is like this:
public abstract class UserBase {
public long UserId { get; set; }
public string Username { get; set; }
}
public class UserTransfer : UserBase, ITransferObject { }
public partial class User : UserTransfer, IModelBase, IDomainObject {
public User() {
Roles = new List<Role>();
}
public virtual ICollection<Role> Roles { get; set; }
}
So far, I've accomplished this:
public static TTransfer CreateTransfer<TTransfer, TDomain>(TDomain d)
where TTransfer : ITransferObject
where TDomain : IDomainObject
{ ... }
This works, because I know the type of TTransfer and TDomain.
And I can call it like: CreateTransfer<UserTransfer, User>(d).
The problem comes when I try create the dto without specifying any type:
CreateTransfer(d);
Of course I've added an overload for this task and I hope I can magically accomplish the following:
public static ITransferObject CreateTransfer(IDomainObject d) {
// do magic
return CreateTransfer<transfer, domain>(d);
}
But in the real world, this is as far as I could get:
public static ITransferObject CreateTransfer(IDomainObject d) {
var dType = d.GetType();
var assemblyName = dType.Assembly.FullName;
var domainName = dType.FullName;
var transferName = domainName + "Transfer";
var domain = Activator.CreateInstance(assemblyName, domainName).UnWrap();
var transfer = Activator.CreateInstance(assemblyName, transferName).UnWrap();
return CreateTransfer< ?, ?>(d); // Problem
}
Both domain and transfer objects are being created correctly.
The main question is: Is there any way to be able to call CreateTransfer<domain, transfer>(d)? Any help will be appreciated.
You can use reflection to call the generic method.
Something like this:
var method = typeof(ClassThatDefinesCreateTransfer)
.GetMethods()
.Single(x => x.Name == "CreateTransfer" &&
x.IsGenericMethodDefinition)
.MakeGenericMethod(dType, transferType);
return (ITransferObject )method.Invoke(null, new object[] { d });
You probably want to cache at least the result of typeof(ClassThatDefinesCreateTransfer).GetMethods().

Categories