Get Relative Path from Route Name - c#

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});

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; }
}

In gRPC unable to bind enum values from message to dontnet core Dto

I need to define a string array type dataType in Grpc message. not sure how to do. right now i am doing it as a
repeated string Title= 1,
here i need name field as string array Type. But it is showing error that it is, field is readonly type when bind data in it:
public override async Task<UserResponse> CreateUser(
UserModel request, ServerCallContext context)
{
var eventResponse = new UserResponse();
var createCmd = new CreateUserCommand
{
Model = new UserDto
{
Title = request.Title,
Id = request.Id,
}
}
}
here in title i need to bind data
The generated code from protoc here gives you something like:
private readonly RepeatedField<string> title_ = new RepeatedField<string>();
[DebuggerNonUserCodeAttribute]
public RepeatedField<string> Title {
get { return title_; }
}
So: Title is indeed read-only. This means that instead of assigning it, you should explore what APIs exist for adding to it - i.e.
var user = new UserDto
{
Id = request.Id,
}
user.Title.Add(request.Title);
// or AddRange, etc
You may still be able to use initializer syntax, too:
new UserDto
{
Id = request.Id,
Title = { request.Title }
}
(which is an .Add)

RouteURL and null issue?

All,
Still learning this stuff so not sure what I am missing.
Here is the path I want to pass to the server.
model.CreditReportHistoryRoute = Url.RouteUrl(CreditReportHistoryDialogController.RouteGetInitialData, new { databaseId = 12345 }).Replace("12345", "{databaseId}");
databaseId is null when I run the code (at the end of the above line).
A few lines above this code runs fine
model.ReportRoute = Url.RouteUrl(RequestReportRoute, new { subjectId = 12345 }).Replace("12345", "{subjectId}");
Here is the controller/route code
public sealed class CreditReportHistoryDialogController : WebAccessApiController
{
public const string RouteGetInitialData = "CreditReportHistoryDialog.GetDataForDatabase";
[Route("{databaseId:int}", Name = RouteGetInitialData), MemberAccess, HttpPost]
public IHttpActionResult GetInitialData(int databaseId)
{
return Ok(databaseId);
}
Thx
jonpfl

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().

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

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;}
}

Categories