How to add tenant / organization id to every URL and read it inside controller - asp.net-core

I am writing an ASP.NET Core web application. In my application, the user can be a member of one or more organizations (this information is stored in the DB). I would like to give the users the possibility to select the context of organization in which the whole app should be running. This context should be passed to every controller so that I can do proper checks and return only the data from the selected org.
In other words, I would like to achieve the state when the user can access the app via:
app.mydomain.com/org1/controller/action/id and using a dropdown they should be able to switch to org2 and access app.mydomain/org2/controller/action/id
In both cases I need to be able to read the organization inside the controller. This should apply to every controller.
How should this be done? Is it possible to construct a route that would handle it and just add new parameter to every controller, e.g. orgId? Or maybe there should be a service that reads this information from the URL and can be injected into controllers? How would the route look then? I have read some tutorials about handling multiple languages in a similar way (with the culture in URL) but I am not able to translate that into my case.

For how to pass the select org id to the controller:
View:
<form action="/Orgnization/Test">
<select id="select" name="select" asp-items="#ViewBag.Sel"></select>
</form>
#section Scripts
{
<script>
$(document).ready(function () {
$("#select").change(function () {
$('form').submit();
});
})
</script>
}
Configure selectlist:
public class HomeController : Controller
{
public IActionResult Index()
{
//for easy testing,I just set it manually...
ViewBag.Sel = new List<SelectListItem>() {
new SelectListItem() { Value = "-1", Text = "--- Select ---" },
new SelectListItem() { Value = "org1", Text = "org1" },
new SelectListItem() { Value = "org2", Text = "org2" },
new SelectListItem() { Value = "org3", Text = "org3" },
};
return View();
}
}
Controller:
public class OrgnizationController : Controller
{
public IActionResult Test(string select)
{
//the select is the value you choose
//do your stuff....
return View();
}
}
If you want to add prefix to the route and get it in the controller:
Startup.cs:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{orgid?}/{controller=Home}/{action=Privacy}/{id?}");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Privacy}/{id?}");
});
Controller:
public class OrgnizationController : Controller
{
public IActionResult Test(string select)
{
var org = "";
if (select==null)
{
var path = Request.Path.ToString();
org = path.Split('/')[1];
}
//do your stuff....
return View();
}
}
Result:

Related

How to display user name instead of id (foreign key) in laravel & vue.js

I want to display the user name instead supervisor_id in the table list in Vue.js. this is one to many relationship. supervisor_id is foreign key from user table.
/// this is view in vue.js. I want to to change work.supervisor_id into something like work.user.name, but it do not work.
<tr v-for="(work,index) in works.data" :key="work.work_id">
<td>{{index+1}}</td>
<td>{{work.work_name}}</td>
<td>{{work.supervisor_id}}</td>
<td>{{work.payment}}</td>
<td>{{work.created_at | myDate}}</td>
<td>{{work.end_date}}</td>
<td>{{work.worker_id}}</td>
<td>
/// this is my script in vue.js
<script>
export default {
data() {
return{
editmode: false,
works:{},
index:1,
users:{},
form: new Form({
work_id:'',
work_name:'',
description:'',
payment:'',
location:'',
end_date:'',
worker_id:'',
application_status:'New',
supervisor_id:'',
})
}
},
methods:{
getResults(page = 1) {
axios.get('api/work?page=' + page)
.then(response => {
this.works = response.data;
});
},
loadWork(){
if(this.$gate.isClerk()){
// axios.get('api/work').then(({data})=>(this.works = data));
axios.get('api/work').then(response => (this.works = response.data));
}
},
/// this is my work controller
public function index()
{
return Work::latest()->paginate(10);
}
the data in the vue.js devtool
For this to work, it would require the a relationship on the Work model which returns the supervisor record which you require.
This will allow you to get the supervisor's (or user's depending on the relationship) name.
Work Model (app\Work.php):
public function supervisor()
{
return $this->hasOne(User::class, 'supervisor_id');
}
Now in your controller, you can use the ->with() eloquent method to eager load a relation:
public function index()
{
return Work::with('supervisor')->latest()->paginate(10);
}
You should now be able to access the supervisor name within vue using:
{{ work.supervisor.name }}
I hope this helps.

Why I can't get into POST processing part of controller in ASP.NET Core application?

I sent data from database to view and showed them in drop-down list. After picking some item I got empty webpage instead of id of picked item along with drop-down list. I discovered that after picking, processing is not continuing in [HttpPost] part of controller.
Here is my controller:
namespace AssetServer.Controllers
{
public class AssetsController : Controller
{
private readonly AssetContext _context;
public AssetsController(AssetContext context)
{
_context = context;
}
// GET: Assets
public async Task<IActionResult> Index()
{
List<Asset> AssetsTableList = new List<Asset>();
AssetsTableList = await _context.Assets.OrderBy(p => p.Ticker).ToListAsync();
ViewBag.AssetsTableList = AssetsTableList.Select(m => new SelectListItem { Text = m.Ticker, Value = m.Id.ToString() }).ToList();
return View();
}
[HttpPost]
public async Task<IActionResult> Index(Asset Asset)
{
ViewBag.SelectedValue = Asset.Id;
List<Asset> AssetsTableList = new List<Asset>();
AssetsTableList = await _context.Assets.OrderBy(p => p.Ticker).ToListAsync();
ViewBag.AssetsTableList = AssetsTableList.Select(m => new SelectListItem { Text = m.Ticker, Value = m.Id.ToString() }).ToList();
return View();
}
}
}
And whole view:
#model IEnumerable<AssetServer.Domain.Assets.Asset>
#using (Html.BeginForm("Index", "Assets", FormMethod.Post))
{
#Html.DropDownList("Title", (List<SelectListItem>)ViewBag.AssetsTableList, new { onchange = "this.form.submit();" })
#ViewBag.SelectedValue;
}
Debugging in Chrome show "500 Internal Server Error":
EDIT:
My routes:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index"},
constraints: new { controller = #"^(?:(?!contact|.well-known|api).)*$" }
);
/* WebAPI routes set with attributes */
routes.MapSpaFallbackRoute(
name: "spa-fallback",
constraints: new { controller = #"^(?:(?!contact|.well-known|api).)*$" },
defaults: new { controller = "Home", action = "Index" }
);
});

how to render date part segments with anchor taghelper in ASP.NET Core

I'm trying to make a blog with a setting that allows a choice between 2 url formats for posts, one with the date as segments and one with only the slug. I want users to be able to choose either of these settings for their blog and it should not require changes in startup code to switch back and forth. In fact I'm trying to support multi-tenant blogs so each blog can have its own url format preference.
I have the following routes defined in Startup.cs
routes.MapRoute(
name: "blogcategory",
template: "blog/category/{category=''}/{pagenumber=1}"
, defaults: new { controller = "Blog", action = "Category" }
);
routes.MapRoute(
"blogarchive",
"blog/{year}/{month}/{day}",
new { controller = "Blog", action = "Archive", month = "00", day = "00" },
new { year = #"\d{4}", month = #"\d{2}", day = #"\d{2}" }
);
routes.MapRoute(
"postwithdate",
"blog/{year}/{month}/{day}/{slug}",
new { controller = "Blog", action = "PostWithDate" },
new { year = #"\d{4}", month = #"\d{2}", day = #"\d{2}" }
);
routes.MapRoute(
name: "blogpost",
template: "blog/{slug}"
, defaults: new { controller = "Blog", action = "Post" }
);
routes.MapRoute(
name: "blogindex",
template: "blog/"
, defaults: new { controller = "Blog", action = "Index" }
);
routes.MapRoute(
name: "pageindex",
template: "{slug=none}"
, defaults: new { controller = "Page", action = "Index" }
);
routes.MapRoute(
name: "def",
template: "{controller}/{action}"
);
routes.MapRoute(
"postwithdate",
"blog/{year}/{month}/{day}/{slug}",
new { controller = "Blog", action = "PostWithDate" },
new { year = #"\d{4}", month = #"\d{2}", day = #"\d{2}" }
);
My Blog controller has these methods related to the post routes
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> Post(string slug, string mode = "")
{
return await Post(0, 0, 0, slug, mode);
}
[HttpGet]
[AllowAnonymous]
[ActionName("PostWithDate")]
public async Task<IActionResult> Post(int year , int month, int day, string slug, string mode = "")
{
...
}
If I manually navigate to
http://localhost:60000/blog/2016/03/07/squirrel
the page works as expected
in my view I'm rendering the link to the post like this with the anchor tag helper
#if (Model.ProjectSettings.IncludePubDateInPostUrls)
{
<a asp-controller="Blog" asp-action="Post"
asp-route-year="#Model.TmpPost.PubDate.Year"
asp-route-month="#Model.TmpPost.PubDate.Month"
asp-route-day="#Model.TmpPost.PubDate.Day"
asp-route-slug="#Model.TmpPost.Slug"
itemprop="url">#Model.TmpPost.Title</a>
}
else
{
<a asp-controller="Blog" asp-action="Post" asp-route-slug="#Model.TmpPost.Slug" itemprop="url">#Model.TmpPost.Title</a>
}
but when I configure it to use the pubDate in the url it renders the link like this:
http://localhost:60000/blog/squirrel?year=2016&month=3&day=7
That url also works but how can I make it render like this:?
http://localhost:60000/blog/2016/03/07/squirrel
I tried also using a named route with the taghelper instead of controller and action, like this:
<a asp-route="postwithdate"
asp-route-year="#Model.TmpPost.PubDate.Year"
asp-route-month="#Model.TmpPost.PubDate.Month"
asp-route-day="#Model.TmpPost.PubDate.Day"
asp-route-slug="#Model.TmpPost.Slug"
itemprop="url">#Model.TmpPost.Title</a>
but that one renders completely wrong without even the slug like this:
http://localhost:60000/blog
I want to make the tagHelper render the url like this:
http://localhost:60000/blog/2016/03/07/squirrel
Can anyone see what I'm doing wrong or not doing right? Or would I need to implement a custom anchor taghelper for this?
ok, I found a solution using the named route, just need to make sure the month and day get formatted as 2 digits, after doing that it now renders as I wanted with the date segments
<a asp-route="postwithdate"
asp-route-year="#Model.TmpPost.PubDate.Year"
asp-route-month="#Model.TmpPost.PubDate.Month.ToString("00")"
asp-route-day="#Model.TmpPost.PubDate.Day.ToString("00")"
asp-route-slug="#Model.TmpPost.Slug"
itemprop="url">#Model.TmpPost.Title</a>

how to pass value ember view to controller

I am new in pretty ember js development .
I have done view below code
{{view "select" content=model prompt="Please select a name" selectionBinding="" optionValuePath="content.body" optionLabelPath="content.title"}}
using following Json
posts = [{
title: "Raja",
body: "There are lots of à la carte software environments in this world."
}, {
title: "Broken Promises",
body: "James Coglan wrote a lengthy article about Promises in node.js."
}];
and Router
App.InRoute = Ember.Route.extend({
model: function () {
return posts;
}
});
My Requirement is passing that combo box selected value to controller
App.InController = Ember.Controller.extend({
alert("combobox selected item")
});
And how an i access that value apicontoller in .net mvc 4
public class ValuesController : ApiController
{
string value= combo box selected value
}
Your "select" view's value attribute needs to be bound to a property on the controller:
add the following to your view's attributes: value=selectedItem
In your controller:
Add "selectedItem"
App.InRoute = Ember.Route.extend({
selectedItem: null,
model: function () {
return posts;
}
});
Now your all set to send it to your Api end point. You could create an action handler and make it happen there. Here is a quick example:
App.InRoute = Ember.Route.extend({
selectedItem: null,
model: function () {
return posts;
},
actions: {
submit: function(){
$.ajax('/api/yourEndPoint', {type: 'POST', data: {body: this.get('selectedItem')} })
}
}
});
In your Handlebars template
<button {[action 'submit'}}>Submit</button>
In your .NET API Controller
public IHTTPActionResult Post(string body){
//.NET's Model Binder will correctly pull out the value of the body keyvalue pair.
//Now do with "body" as you will.
}
You should really look into using Ember-Data, it's freaking awesome.
You only need to set the selectionBinding="someModelAttribute" and the two way data binding will take care of setting the selected value on the model.

ASP.NET MVC4 View Model Parameter Null when Posted

I want to use a view model as input to an Edit form. Call it -
public class StudentEditViewModel
{
}
My Edit action method creates the object and passes it to the Edit view, which has #model set to StudentEditViewModel. This works fine - all data is displayed as expected.
BUT, when I post the changes (using ) things fall apart. Here is the skeleton of my action handler:
[HttpPost]
public ActionResult Edit(StudentEditViewModel student)
{
}
The problem is that "student" is null. All the online examples appear to do it this way, but I'm obviously missing something. Can anyone help me out?
I'll be happy to provide more details if necessary. Thanks in advance.
Your StudentEditViewModel needs properties (E.g public string name { get; set;}) because the StudentEditViewModel should have a property basis for it to have a value and in your view, use the basic LINQ syntax
using(Html.BeginForm())
{
#html.TextBoxFor(u => u.name)
<input type="submit"/>
}
Try adding also with a non-Data annotation ActionResult and check out the breakpoints. This was my mistake before when I tried to program. Hope I can help you.
Are you using Explicitly typed View Model? In this case you can do it by jquery as follows:
$("#btnSave").click(function (event) {
event.preventDefault();
if ($("#form1").valid()) {
var formInput = $('#form1').serializeObject();
$.ajax({
type: 'POST',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
url: 'your controller action url be here',
data: JSON.stringify(formInput)
})
.done(function (data, textStatus, jqXHR) {
showMsg('page-message', 'success', 'Success!', 'The item was saved.');
$('#PriorityDateId').val(data);
window.location.href = 'after save where you want to redirect(give url)';
})
.fail(function (jqXHR, textStatus, errorThrown) {
showResponse('page-message', 'error', 'Error!', jqXHR.responseText);
});
}
});
If need more info, let me know..
Your model should contain some properties like so:
model:
public class StudentEditViewModel
{
//Sample Properties
public string Name{get;set;}
public int Age {get;set;}
}
And your view should look something like this.
#model Nameofyourproject.Model.StudentEditViewModel
#using(Html.BeginForm())
{
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name) // this where you will enter a value for the Name property
#Html.LabelFor(m => m.Age)
#Html.TextBoxFor(m => m.Age) // this where you will enter a value for the Age property
<input type="submit"/> //this will submit the values to your action method.
}
you will be able to get this values now in your action method
[HttpPost]
public ActionResult Edit(StudentEditViewModel student)
{
var name = student.Name;
var age = student.Age;
}