I am new to programming. How can I create a custom URL for each user to retrieve data for the entered user? For instance, www.hellothisis.com/sirushti
I understand that it's very difficult in the beginning. However, have you read the introduction to MVC? There you will understand the basics and go further.
Even though you need to read that, the answer to you question is: this
You will see the default router and the "/sirushti" is the ID. In the controller you will likely to have something like this:
public JsonResult GetUser(string alias) { ... }
Take a look on the links I've sent you and you will get what it takes to use MVC!
Related
I am trying to build sth pretty simple, but I try to do it the correct way. But I struggle to figure out what is best.
I have a process chain where the user has to fill in some fields in different forms. Sometimes it depends from the user inputs which form the user is shown next.
[HttpGet]
public IActionResult Form1(Form1Vm f1vm)
{
return View(f1vm);
}
[HttpPost]
[ActionName("Form1")]
public IActionResult Form1Post(Form1Vm f1vm)
{
//process the data etc
//prepare the new viewmodel for the next form view (f2vm)
//Option1:
return View("Form2", f2vm);
//Option2:
return RedirectToAction("Form2", f2vm);
//for Option 2 I would need an additional HttpGet Action Method in which I
//would have to call Modelstate.Clear(); in order to not have the
//immediate validation errors on page load
//also all the properties of my viewmodel are passed as get parameters
//what looks pretty nasty for me
}
//More form views action methods should be added here...:
What is the better way? As mentioned in my comments above I have quite a big disadvantage for using the RedirectToAction option. However if I use the direct View(); call, I don't take care on https://en.wikipedia.org/wiki/Post/Redirect/Get and the user cannot simply refresh a page without getting a warning that his form is submitted once again.
Do I miss another way or don't see something obvious?
Edit: I just thought about a 3rd way, which I have seen quite often: Not transfering the whole VM to a HttpGet method but only the ID. I'd then have to load all the data stored previously directly from the db, map it again to my new VM and then call the View(); with this VM. Right now I think this is the "best" solution, however I feel like it is pretty laborious...
As per the dicussions, I would suggest using depending on your preference :
1) Save to db at the end of each form post and as you suggested use the I'd to redirect to a GET.
2) Depending on the the number of form pages and your requirements, retrieving values that a form needs on the get would be standard practice. This ensures that if a user drops off a form at any stage you can then start them off where they left off.
3) I wouldn't setup the viewmodel for the next form in the post of the previous. Generally as part of the single responsibility principle you want to ensure that your methods have only one reason to change.
4) PostRedirectGet pattern should be implemented with this to ensure data is not saved multiple times if a user refreshes after a post.
I have been reading and searching for a best practice for doing this.
I am "learning" about Web ASP .NET MVC and also Web Api 2.2.
I am in the point of Authentication and Authorization, I clearly understand the meanning and difference in one and another. My problem come with Authorization, I already know allow/deny access using Filter and use Roles.
But beside that I dont know where to implement the logic for authorize to some user to do some action, or to see some data, for example:
A user is Authenticated already and have the role Pilot
This user enter to a controller/action for example flight/getPassengers/1
Where getPassengers is an action to retreive all the passengers for the flight #1
Let's imagine that the current logged user on the role Pilot wants to view the list of that flight because He is allowed to, but he can't see the passengers of all flights, for example flight/passengers/3 the flight #3 is from another user Pilot.
Where is the best place to put this validation logic?
Inside the action: getPassengers? I don't think so, because if later in this controller (flight) we need validate if the same info belongs to the current user (pilot) we would have to repeat that piece of code (DRY)
So, maybe a Custom Filter?
I find an article (here) but I am not Sure if is in there and How gets implementated. I have an Implementation, something like this:
Public Class CustomFilter
Inherits ActionFilterAttribute
Implements IActionFilter
Public Overrides Sub OnActionExecuting(filterContext As ActionExecutingContext)
MyBase.OnActionExecuting(filterContext)
End Sub
Public Overrides Sub OnActionExecuted(filterContext As ActionExecutedContext)
MyBase.OnActionExecuted(filterContext)
End Sub
End Class
Is creating this type of Filters and after that using this on Controllers/Actions the correct way to achieve this?
Or how is this type of logic handled?
Thanks for your suggestions
You should implement a custom AuthorizeAttribute where you can encapsulate this logic. Just be careful in the way you implement them, try not to have several Authorize Filters. It could impact the perfomance of your application. Design a good one that can be used widely.
I have an ASP.NET MVC website, where most of my controllers are decorated with Authorize attributes, to enforce forms authentication.
I'm about to make this website available on Facebook via a Facebook app, but for my FB users I want to use a different authentication/authorization, I want to use CanvasAuthorize attribute on my controllers.
The problem is that I can't use both on my controllers/actions, because then both of them would be enforced to access the relevant action, but I want only Authorize for the normal website and I want only the CanvasAuthorize when the website is accessed from FB (via FB app).
I started to
refactor hugely my existing controllers to 'controllerhelpers'
make existing controllers (with authorize attribute) use the controllerhelpers relevant method
create new controllers (decorated with CanvasAuthorize) for the FB-app, which use the relevant controllerhelper methods also
But this is huge work, and I'm not sure whether this is the way to go, or there is a much easier an elegant way to work.
Of course I want to use the same views, and in my cshtmls I'm using specific controllers's Url.Action methods, so with my current approach when I'm inserting action-paths in my cshtmls (for eg. jQuery ajax Url properties) I have to make an if-statement to use for example the 'PersonalController' when the normal website is used and use the 'FBPersonalController' when the website is used as a FB app.
In this case PersonalController is decorated with [Authorize] and FBPersonalController is decorated with [CanvasAuthorize].
So, any feedback is appreciated ;)
Thanks!
Xoyoja's answer lead me to this solution. I don't mark it as 'accepted answer' because I'm evaluating it, but maybe it is worth discussing:
No, not all of them should be decorated. But with your proposal, I came to the following:
IEnumerable<Func<ControllerContext, ActionDescriptor, object>> conditions =
new Func<ControllerContext, ActionDescriptor, object>[] {
(ctrlCtx, actDesc) =>
{
if(FacebookWebContext.Current.SignedRequest != null)
{
return new CanvasAuthorize();
}
else
{
if(ctrlCtx.Controller.GetType() == typeof(AccountController)
&& actDesc.ActionName == "LogOn")
{
return null;
}
return new AuthorizeAttribute();
}
},
};
When my website is accessed from FB, it seems that the SignedRequest is not null, so the CanvasAuthorize can be used.
If my website is accessed from it's normal published url, then I use the AuthorizeAttribute.
The AccountController and "LogOn" action-specific logic is required to allow logging in to the website from the public url. From Facebook the Context contains the Facebook UserID which would implicitely do the authentication.
I'm still thinking about implications, worst-case-scenarios, backdoors whether this could harm me or not.
Can you use Conditional Filter to support both [Authorize] and [CanvasAuthorize]? As I tested in a simple ASP.NET MVC3 application, it works. Do you think it helps?
On the other hand, a nice solution would be, if you could change your design, put the authentication stuff in one place, that is, FormsAuthenticationService, FacebookAuthenciationService, and OpenIDAuthencitationService implement an interface called "IAuthenticationService". Call the standard FomsAuthentication.SetAuthCookie method upon completing the Facebook OAuth flow. The Authorize attribute should then work properly. Refer to this question and check code snippets from here (Create.aspx and SessionController.cs). Please evaluate.
Hi all hope you can help.
I am primarily a windows developer (winforms and wpf/mvvm) and it's been 10 years since my last web application, so this is probably a daft question.
I have just redeveloped a customer satisfaction questionnaire and as I had to figure out this from scratch thought I would use MVC 3 and Razor.
The Questionnaire is a single page web site with a controller that looks something like this.
Function Index(BrandName As String, CaseID As Integer, EventID As Integer) As ActionResult
ViewData("Scores") = Scores
Dim questionnaire As New Questionnaire
questionnaire.CaseID = CaseID
questionnaire.EventID = EventID
questionnaire.BrandName = BrandName
//Get Some specific branding from the database
questionnaire.FullBrandName = "FullNameFromDatabaseTable"
Return View(questionnaire)
End Function
Function Save(questionnaire As Questionnaire) As ActionResult
If TryUpdateModel(questionnaire) Then
SaveQuestionnaireToDatabase(questionnaire)
Else
Return RedirectToAction("Index")
End If
Return View()
End Function
I have stripped out some database code and some stuff to get a signed image url as i don't think its relevant.
I am not sure I fully understand the magic that is happening between view and controller which is the real reason for my question.
This is going up into azure along with everything else, I am asking the question about session state because this will be load balanced accross two instances. No authentication is required to access the page as it can only be completed once.
Many Thanks
p.s I couldn't get vb style quotes to work so put in the c# one.
It doesn't look like you are doing anything that touches the session, so there's no concern about which server the post goes to. All the information to process the request is submitted with the form.
You can take a look here (specifically section titled Implementing Add New Product ) to remove some of the mystery of how form data is mapped back to server side information.
If you have any content that needs to be shared / accessed across instances, simply use the AppFabric Cache, which went live about two weeks ago. I provided a link in this SO answer. The nice thing is that you can use the cache provider with just a few lines of code to set up, then call Put() and Get() for serializable key/value pairs. When you set up the cache, you can also enable a custom asp.net session state provider with a simple web config change - the Azure portal will auto-generate the xml for you.
If this is a duplicate, please let me know - because i had a quick look and couldn't find anything that really answers my question.
I'm experimenting with ASP.NET MVC 2. Now coming from a Web Forms background, i only really dealt with HTTP GET and HTTP POST.
I'm trying to see how i could apply GET/PUT/POST/DELETE to the respective CRUD operations on my repository (Find, Insert, Update, Remove).
Say i have a single controller, with the following action methods:
[HttpGet] // GET: /Products/{id}
[ActionName("Products")
public ActionResult Get(int id = 0) { ... }
[HttpPut] // PUT: /Products
[ActionName("Products")
public ActionResult Put(Product product) { ... }
[HttpPost] // POST: /Products/{product}
[ActionName("Products")
public ActionResult Post(Product product) { ... }
[HttpDelete] // DELETE: /Products/{product}
[ActionName("Products")
public ActionResult Delete(Product product) { .. }
Couple of questions on that - is that how you would name/separate the action methods? Should i be passing through the entire model (Product), or just the id?
The problem i'm having is i'm not sure how to handle invoking these action methods with the relevant HTTP Verb in my View.
At this stage, I'm thinking i would have 3 Views:
"Index" - bind to IEnumerable<Product> model, listing all products, with "Edit", "Details" and "Delete" links
"Single" - bind to single Product model, listing all details for a product, with an "Update" button.
"New" - bind to single Product model, with form for creating product, with an "Create" button.
So - my question is, how do i specify i want to invoke a particular controller method with a specific HTTP Verb?
With Html.BeginForm, you can specify a FormMethod enumeration - but it only has GET and POST.
How can i perform a PUT and DELETE command?
Will i need a seperate View for each HTTP Verb?
If i have a link called "Delete", can i invoke a HTTP DELETE command to my controller, or does it need to be redirected to a new View with the form action delete?
Or, is this a silly/overkill design in the first place, should i just stick with "GET" and "POST"?
I'm (fairly) new to this style of web development (REST), so please be kind. :)
UPDATE
So i came across this interesting article from Stephen Walther, regarding this very topic.
He indicates a HTML Form only supports GET and POST (because i'm new to REST-style web development, i did not even know this, to which i am partially ashamed).
Apparently the only way to invoke a Controller action with PUT/DELETE is to do it with AJAX. Seriously?
So what should i do here, should i stick with GET/POST, or should i create a JavaScript file which wraps the underlying XmlHttpRequest code behind a nice function?
Which way are ASP.NET MVC developers leaning? Surely someone has asked themselves this same question.
The reason that you're mostly familiar with GET and POST is because a regular old browser can only GET or POST a URL, especially when submitting a form.
Setting up your controllers this way, you're looking at something more along the lines of a REST API vs. a web site at least in spirit.
And yes, you are correct that only AJAX requests can set their request methods explicitly, so you're good to go if you'll be performing actions like deleting products via AJAX (in which case I would suggest only passing the ID since it is much lighter than serializing the entire product and you'll likely have easy access to the ID in your markup).
Here's the thing. If you are building a modern web application you're probably using AJAX and without getting too dogmatic you should expect your users to have JavaScript. If you want to do CRUD without AJAX then you can always POST a Product or use GET for a delete method with the ID in the URL (caveat to that, make sure the Delete method is protected behind authorization or a web crawler will gladly consume your GETs and delete all your data...)
If you don't want to build a REST API then don't sweat the fact that you're not using DELETE (just use GET with the ID in the URL) or you're not using PUT (just use POST with the product entity in the POST body).
REST is a great style for building APIs (no presentation tier, data sent in raw format to clients who consume them, could be a phone or a website, etc.) over HTTP. HTTP is great on its own for building web pages. Use what you need for what you need it for.
If you want to build a REST API to be used by both other people AND your web site, then do that, and just have your site's controller action methods call your API methods directly. I do that all the time. Use a web client like Hammock to make it easier on you.
Personally I stick to as simple as possible full requests, instead of going AJAX all over. I use ajax, but in specific places where it enhances the experience (and I do with a progressive javascript approach).
Because of the above, I always just use GET and POST.
As for the naming, for those I'd do: Get, Update, Create, Delete, which makes it pretty clear. I actually use more like an action name that's related to what the operation does, but for simple things those work fine.
HtmlHelper.HttpMethodOverride Method (System.Web.Mvc)
How about this?