I have a question about MVC asp.net
I have a link that provides a data using HTTP in this XML format
[...]
<Item>
<Name>Money</Name>
<Unit>1000</Unit>
</Item>
[...]
If I want this to display data on view in my application - what should I use? WebAPI?
The data ( < unit > ) change every few minutes, so always view have to display the current data.
Data are also possible to get in JSON format.
To clear up the confusion from all existing answers and comments: your actual problem statement is this:
I have a third-party URL that when requested, gives you some JSON which I wish to display in a table on an MVC view.
This is very trivial. See Deserializing JSON into an object to generate classes to deserialize the JSON. This provides you with a statically typed class that you can use from code.
Then you define a view model to hold a list of items:
public class JsonViewModel
{
public List<JsonItem> Items { get; set; }
}
public class JsonItem
{
public string Name { get; set; }
public string Unit { get; set; }
}
And in the controller you perform an HTTP GET request to retrieve the JSON (HTTP GET request and XML answer), parse it, map it to your view model and return it to your view:
public class FooController : Controller
{
public ActionResult Index()
{
// 1. Perform HTTP request to retrieve the JSON.
var webClient = new WebClient();
string rawJson = webClient.DownloadString("json-url");
// 2. Parse the JSON.
var jsonRootObject = JsonConvert.DeserializeObject<JsonRootObject>(rawJson);
// 3. Map to your viewmodel
var viewModel = new JsonViewModel
{
Items = jsonRootObject.Items.Select(i => new JsonItem
{
Name = i.Name,
Unit = i.Unit
}).ToList()
};
// 4. Return the model to your view
return View(viewModel);
}
}
Then finally you render the model in your view:
#model JsonViewModel
<table>
<tr>
<th>Name</th><th>Unit</th></tr>
</tr>
#foreach (var item in Model.Items)
{
<tr>
<td>#item.Name</td><td>#item.Unit</td>
</tr>
}
</table>
In your controller, call the external service to get the data. Can be XML, but JSON is more lightweight; I'd go for that. Parse the data into a view model that you then pass to the view. The view model contains the parsed information in the format that is best suited for your view; this will make sure your view can be kept as simple as possible (focusing on view logic).
To keep your controllers light, you might want to decide to move the retrieval and parsing logic in dedicated components, and use those from within your controller.
Basically, what to use - JSON or View - is fully up to you and depends on your knowledges.
You can reach what you need here using JSON(or even XML) and js code in the page, or partial view and less js code.
I'd suggest you to return partial view from your MVC controller and update whole block.
You can simply use a periodic ajax call using setInterval to the 3rd party endpoint and then update your view accordingly.
A better approach would be to use MVVM so you just need to update the view model and the framework will do the rest.
If you want to decouple your site from the 3rd party or you just want to hide that 3rd party address, You can use Web Api to call the 3rd party endpoint and call the web api endpoint from the client.
You will need to handle CORS this way, if the web api is in a different domain.
You can also use mvc action instead of the web api but if you're planning on building large scale application. It's better that you start using SOA Architecture.
I prefer Json instead of Xml because it is lightweight, so... you can go through three different ways:
Create a method that returns a JsonResult in your Controller (that is what i think you are doing) inside your asp.net mvc application;
Create a WebApiController inside your asp.net mvc application just to have the web api stuff without creating a new application;
Create a Web Api application and return your data (if you need only one service, i don't think you should create a new app for that, it is too much work)
If you choose the third option and you are not familliar with Web Api, i will recommend you to read this.
Related
I'm learning ASP.NET Core and I have some doubts about the loading of an heavy collection of records, let me explain better.
What I'm trying to do
In my application, after the login execution, the user will redirected to the Dashboard Home View. The Dashboard is the place that contains all the functions for an user. The Dashboard Controller have also other Views like:
Home
Analysis
Performance
Now each View need to display to the user a Table which contains a list of Products, at the bottom of this Table there is the content of the View.
Problem
First problem: is the Table redundancy code, which I solved creating a _PartialView that contains the html of the Table that contains the products to display. Coming from c# + WPF I used the same logic of UserControl, so this is a good solution for me.
Second problem: the products to display inside the Table, these products are downloaded from an API, now as I said before, these records must be always displayed in the products Table (which is available in different View using the _PartialView). Imagine that every time the user click on a Dashboard item (which load a Dashboard View), the Dashboard Controller will call this method:
public async Task<List<Products>> GetProducts(string date)
{
var client = new RestClient(Url);
var request = new RestRequest("product/get_products/{date}", Method.GET);
request.AddUrlSegment("date", date);
var cancellationTokenSource = new CancellationTokenSource();
var response = await client.ExecuteTaskAsync(request, cancellationTokenSource.Token);
List<Products> products = JsonConvert.DeserializeObject<List<Product>>(response.Content);
return products;
}
For me, this is not a really good practice because each time the _PartialView will call this method and reload the data, so I need to store somehow this data (a temp store). How can I store these records to the user session without reload each time the _PartialView being called?
Between, I have some doubts about the API method:
Should I place all the API calls inside the Service folder? Repository folder? Or Controller folder?
Folder tree
View <- Folder
Dashboard <- Folder
Home
Analysis
Performance
_ProductsTable
The View Home, Analysis, Performance load _ProductsTable in the following way:
#await Html.PartialAsync("_LeftSidebar")
Use view components. They're essentially self-contained modules of functionality that return views, which you can embed in other views, without main view or action having to know about any of it.
First, create a directory call ViewComponents. Inside add new class, like ProductsViewComponent. Then, you'll want something like:
public class ProductsViewComponent : ViewComponent
{
private readonly HttpClient _client;
public ProductsViewComponent(HttpClient client)
{
_client = client ?? throw new ArgumentNullException(nameof(client));
}
public async Task<IViewComponentResult> InvokeAsync(string date)
{
using (var response = await _client.GetAsync($"/"product/get_products/{date}"))
{
response.EnsureSuccessStatusCode();
var products = await response.Content.ReadAsAsync<List<Product>>();
return View(products);
}
}
}
Then, create the view, Views\Shared\Components\Products\Default.cshtml. Inside, add the HTML to render your list of products. Finally, where you want the product table to appear add:
#await Component.InvokeAsync("Products", new { date = myDate })
The above code uses HttpClient rather than RestClient, since honestly, it's completely unnecessary at this point to have a separate library for making HTTP calls. HttpClient is built-in and has been extended with functionality in Core to make this much easier, such as the ReadAsAsync method used above, which transparently deserializes your JSON response into the generic type argument. Additionally, you now have things like IHttpClientFactory which ensures that you have properly scoped HttpClient instances. As a result, the above code also assumes adding something like the following to your Startup.cs:
services.AddHttpClient<ProductsViewComponent>(c =>
{
c.BaseAddress = new Uri('https://api.myservice.com');
// add default headers and such if you need them
});
You can also then use the Polly integration to setup automatic retries, circuit breakers, etc., allowing you handle all sorts of API scenarios such as temporarily unavailable, rate limits, etc. See the full documentation for both IHttpClientFactory and its Polly integration for more info.
Lastly, if this is a scenario where you don't need realtime data, you can also inject an instance of IDistributedCache into your view component and add logic to set the result of your API call in that, and retrieve it from there first, before making the call again, allowing you to significantly reduce the load both on your app and the API (especially if do have something where rate limits apply).
I have been struggling on trying to work this for the last 3 days, how do you pass data from an api controller into an mvc controller and use the data to populate a selectlistitem.
I have seen plenty of examples of calling the api from the webpage which is all well and good, but what if the user has javascript disabled, it will not display the data.
So any help with an example for this would be much appreciated.
My code is:
web.api
public IEnumerable<DisplayCurrencyInDDL> GetCurrencyForDDL()
{
var s = _ICurr.InsetCurrencyIntoDataBase();
return s.AsEnumerable();
}
mvc controller
WebClient wc = new WebClient();
var s = wc.DownloadString("http://localhost:50687/api/Currency");
How do I get the value from var s (currency and currencyid) into a selectlistitem.
Thanks
George
edit data returned as: [ { "strCountry": "Afghan Afghani", "strCountryCode": "AFN" }, { "strCountry": "Albanian Lek", "strCountryCode": "ALL" }, { "strCountry": "Algerian Dinar", "strCountryCode": "DZD" }, { "strCountry": "Andorra Euro1",
I don't understand why you are doing it this way.
If you want to share some code you can do this by moving the code into
some Library and instantiate that class in WebAPI and also in your MVC
Controller.
Ok, so after reading this post on stackoverflow difference between apiController and controller
Its my understanding that if i'm returning data to my own website, then use mvc controller, but if i'm allowing a 3rd party to consume data from my site, then put the data in an api controller.
Also if a user visited my site/your site and had javascript disabled, then json would not work on the client side as requires jQuery etc, so my understanding is use api if you are sure the visitor will not have javascript disabled.
Please let me know if that correct
I am pretty sure I am doing something wrong here. I have been developing a web app using MVC and Razor and I never thought of using the form element. Now so much has already been done with master pages and sub pages that it means restructuring most of our code in order to use form element and the would result in multiple form elements on a page.
That aside, in Asp.Net if I wanted to access any control in the C# code behind I could just give it an ID="SomeID" and a RUNAT="SERVER". Then in my code behind I could set its value and properties.
When I do this in Razor, I use lines like:
<input id="hiddenPostBack" runat="server" type="hidden" />
Why can't I access this in the controller? I want to detect a postback and set the value to false if it is the first time the page loads, and if not, then set the value to true. Then based on this, I will read it either server side or client side and do something.
My real question is, how do I "do something" both server side and client side given that I don't have a form element. I was under the impression that if I wanted to pass values from client to server and back, the easiest way to do this is with a hidden input. But I am just not getting how to accomplish this with MVC3 and razor.
A move from WebForms to MVC requires a complete sea-change in logic and brain processes. You're no longer interacting with the 'form' both server-side and client-side (and in fact even with WebForms you weren't interacting client-side). You've probably just mixed up a bit of thinking there, in that with WebForms and RUNAT="SERVER" you were merely interacting with the building of the Web page.
MVC is somewhat similar in that you have server-side code in constructing the model (the data you need to build what your user will see), but once you have built the HTML you need to appreciate that the link between the server and the user no longer exists. They have a page of HTML, that's it.
So the HTML you are building is read-only. You pass the model through to the Razor page, which will build HTML appropriate to that model.
If you want to have a hidden element which sets true or false depending on whether this is the first view or not you need a bool in your model, and set it to True in the Action if it's in response to a follow up. This could be done by having different actions depending on whether the request is [HttpGet] or [HttpPost] (if that's appropriate for how you set up your form: a GET request for the first visit and a POST request if submitting a form).
Alternatively the model could be set to True when it's created (which will be the first time you visit the page), but after you check the value as being True or False (since a bool defaults to False when it's instantiated). Then using:
#Html.HiddenFor(x => x.HiddenPostBack)
in your form, which will put a hidden True. When the form is posted back to your server the model will now have that value set to True.
It's hard to give much more advice than that as your question isn't specific as to why you want to do this. It's perhaps vital that you read a good book on moving to MVC from WebForms, such as Steve Sanderson's Pro ASP.NET MVC.
If you are using Razor, you cannot access the field directly, but you can manage its value.
The idea is that the first Microsoft approach drive the developers away from Web Development and make it easy for Desktop programmers (for example) to make web applications.
Meanwhile, the web developers, did not understand this tricky strange way of ASP.NET.
Actually this hidden input is rendered on client-side, and the ASP has no access to it (it never had). However, in time you will see its a piratical way and you may rely on it, when you get use with it. The web development differs from the Desktop or Mobile.
The model is your logical unit, and the hidden field (and the whole view page) is just a representative view of the data. So you can dedicate your work on the application or domain logic and the view simply just serves it to the consumer - which means you need no detailed access and "brainstorming" functionality in the view.
The controller actually does work you need for manage the hidden or general setup. The model serves specific logical unit properties and functionality and the view just renders it to the end user, simply said. Read more about MVC.
Model
public class MyClassModel
{
public int Id { get; set; }
public string Name { get; set; }
public string MyPropertyForHidden { get; set; }
}
This is the controller aciton
public ActionResult MyPageView()
{
MyClassModel model = new MyClassModel(); // Single entity, strongly-typed
// IList model = new List<MyClassModel>(); // or List, strongly-typed
// ViewBag.MyHiddenInputValue = "Something to pass"; // ...or using ViewBag
return View(model);
}
The view is below
//This will make a Model property of the View to be of MyClassModel
#model MyNamespace.Models.MyClassModel // strongly-typed view
// #model IList<MyNamespace.Models.MyClassModel> // list, strongly-typed view
// ... Some Other Code ...
#using(Html.BeginForm()) // Creates <form>
{
// Renders hidden field for your model property (strongly-typed)
// The field rendered to server your model property (Address, Phone, etc.)
Html.HiddenFor(model => Model.MyPropertyForHidden);
// For list you may use foreach on Model
// foreach(var item in Model) or foreach(MyClassModel item in Model)
}
// ... Some Other Code ...
The view with ViewBag:
// ... Some Other Code ...
#using(Html.BeginForm()) // Creates <form>
{
Html.Hidden(
"HiddenName",
ViewBag.MyHiddenInputValue,
new { #class = "hiddencss", maxlength = 255 /*, etc... */ }
);
}
// ... Some Other Code ...
We are using Html Helper to render the Hidden field or we could write it by hand - <input name=".." id=".." value="ViewBag.MyHiddenInputValue"> also.
The ViewBag is some sort of data carrier to the view. It does not restrict you with model - you can place whatever you like.
As you may have already figured, Asp.Net MVC is a different paradigm than Asp.Net (webforms). Accessing form elements between the server and client take a different approach in Asp.Net MVC.
You can google more reading material on this on the web. For now, I would suggest using Ajax to get or post data to the server. You can still employ input type="hidden", but initialize it with a value from the ViewData or for Razor, ViewBag.
For example, your controller may look like this:
public ActionResult Index()
{
ViewBag.MyInitialValue = true;
return View();
}
In your view, you can have an input elemet that is initialized by the value in your ViewBag:
<input type="hidden" name="myHiddenInput" id="myHiddenInput" value="#ViewBag.MyInitialValue" />
Then you can pass data between the client and server via ajax. For example, using jQuery:
$.get('GetMyNewValue?oldValue=' + $('#myHiddenInput').val(), function (e) {
// blah
});
You can alternatively use $.ajax, $.getJSON, $.post depending on your requirement.
First of all ASP.NET MVC does not work the same way WebForms does. You don't have the whole runat="server" thing. MVC does not offer the abstraction layer that WebForms offered. Probabaly you should try to understand what controllers and actions are and then you should look at model binding. Any beginner level tutorial about MVC shows how you can pass data between the client and the server.
You are doing it wrong since you try to map WebForms in the MVC application.
There are no server side controlls in MVC. Only the View and the
Controller on the back-end. You send the data from server to the client by
means of initialization of the View with your model.
This is happening on the HTTP GET request to your resource.
[HttpGet]
public ActionResult Home()
{
var model = new HomeModel { Greeatings = "Hi" };
return View(model);
}
You send data from client to server by means of posting data to
server. To make that happen, you create a form inside your view and
[HttpPost] handler in your controller.
// View
#using (Html.BeginForm()) {
#Html.TextBoxFor(m => m.Name)
#Html.TextBoxFor(m => m.Password)
}
// Controller
[HttpPost]
public ActionResult Home(LoginModel model)
{
// do auth.. and stuff
return Redirect();
}
Withing a Silverlight Application, how does one get the ID from the URL when using MVC given the URL in the standard MVC Format {controller}/{action}/{id}
Is there anything MVC specific or does one need to parse this URL 'manually'?
Well that's simple, either look in Request.Params["id"] or - and that's more ellegant - add a argument with the name "id" to you Controller method (case does not matter).
public void Index(string id) { }
Works even for more complex objects, the MVC does a good job in retrieving the information and matching it to the arguments of the controller method.
public class Data {
public string ID { get; set; }
}
public void Index(Data data) {
// data.id should be set
}
Silverlight runs on the client, therefore it cannot access the values on the server. However, the sever can pass the info to the client.
My first try of MVC. Am trying to implement a simple example. Inspiration from here. Have I got this pattern (yet!)?
View: "Hey, controller, the user just told me he wants the first person"
Controller: "Hmm, having checked his credentials, he is allowed to do that... Hey, model, I want you to get me the first person"
Model: "First person... got it. Back to you, Controller."
Controller: "Here, I'll collect the new set of data. Back to you, view."
View: "Cool, I'll show the first person to the user now."
View:
namespace WinFormMVC
{
public partial class Form1 : Form
{
controller cont = new controller();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = cont.checkPermissionsAndGetFirstPerson();
}
}
}
Controller:
public class controller
{
public string checkPermissionsAndGetFirstPerson()
{
string returnValue = "";
if (checkPermissions())
{
model m = new model();
returnValue = m.getFirstPerson();
}
return returnValue;
}
public bool checkPermissions()
{
return true;
}
}
Model:
public class model
{
public string getFirstPerson()
{
return "Bill Smith";
}
}
Hmm... I am not sure if I'd call this MVC... As with ASP.NET WebForm, this form is more like an MVP pattern.
As per my understanding, in MVC, controller is the one responsible for managing all resources and flow of the code. In your example, you basically creating a Windows Form first (the view) and then attach a controller to it which is more of a MVP sort of things.
In a classical MVC pattern, the Model, once instantiated, will be linked to the View and when the model changes, the view will get notified (possibly through Observer / PubSub pattern).
Button click, etc. from the View will be routed to the controller which will coordinate those sort of stuffs.
see: this.
I would describe MVC more like this:
Request (MVC url routing, some event passed from previous UI etc)
Controller - check credentials, get data, return Model
Model - represents the data passed back from the Controller
View - render the Model returned by the Controller. Depending on the Model may display UI to initialise new Controller actions. May also pass Model back to next Controller action.
I think it can be a little confused because in many Model implementations (such as Linq) they provide data definition and access, but it's still the Controller that knows where to start (even if it's the Model that knows how to save its own changes).
So, your code should be something like:
//Controller:
public class PersonController
{
public PersonAction Detail(int personId)
{
Person returnValue;
//get person from DB and populate returnValue
return new PersonAction( returnValue );
}
}
//Model:
public class Person
{
public string FirstName {get; set;}
public string LastName {get; set;}
}
//View:
public partial class PersonDetailView : MVCForm<Person>
{
public Form1( Person model ):base(model) {
textBox1.Text = model.FirstName + " " + model.LastName;
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = model.FirstName + " " + model.LastName;
}
}
What this example is missing is the framework that makes this all possible - there are two significant parts to that:
Something that takes/parses parameters and based on that calls a controller's action method. For instance in Asp.net MVC this is the routing handlers - the call above would be the request url: ~/Person/Detail/personId
Something that takes the result from the action (PersonAction in the example above) and finds the correct view to display. In this example it would open a PersonDetailView form and pass the Person model to it.
There are lots of example frameworks for an MVC implementation for WinForms - one of them may be a good starting point.
To adopt the MVC pattern you want to implement the following:
The view hooks up to the Model and listens for changes.
The controller hooks up to the view and handles specific events i.e. button presses etc
The model processes requests made by the controller and notifies the view.
I agree with Jimmy you would want to integrate something like the Observer pattern to this type of system so its possible for the Model to inform the View when it changes so the View can then update itself accordingly.
The difference with MVP is it introduces a Presenter class which monitors the Model on behalf of the View, in other words the View doesn't know about the Model, it only knows about its Presenter. The Presenter responds to changes in the Model and updates the View accordingly.
I think there are a few corrections to be made to your narrative. Strinctly speaking the view does not contact the controller, the user contacts the controller directly. In a web app it looks like this.
User: Hey web app, can I have the resource at /people/1
Routing engine: That means you person controller. get the first user.
User controller: Model, I need you to get me user record for the authenticated user, and the person record for the first person.
User Controller: Right. I know the authenticated user is an admin, and person one does exist. So return the Admin view for person to the user.
Rendering engine: Build up the html from the view (template) and person object (data)
This is difficult to do in webforms. I guess the best way is to have a page for each controller, and have that page dynamiclly choose and display a user control. One for each view. It is important in MVC that the view is dumb. All requests are handled directly by controllers, which then select which view to use.
Your checkPermissionsAndGetFirstPerson method is probably doing too much. Authorization and fetching data should probably be separate operations.
Also, if your Form1 class is your view, it probably shouldn't be constructing the controller. That seems backwards.
Most information you'll find on MVC in .NET will be for ASP.NET MVC web applications. You might want to check out the WinFormsMVC project on CodePlex to see how someone else has tackled this problem.
http://winformsmvc.codeplex.com/
Here's another WinForms MVC implementation on CodePlex. Looks like it's got a bit more documentation.
http://koosserymvcwin.codeplex.com/
You might find this tutorial very helpful: http://nerddinnerbook.s3.amazonaws.com/Intro.htm. Written by Scott Guthrie, it explains the MVC workflow very well. Part 4 should have the basics you're looking for.