I am new to ASP.NET MVC. I have RestCallcontroller class. I want to pass data from Restcontroller to Home Controller.
This is theRestController
public class RestCallController : Controller
{
public string loginJsonString;
Result result = new Result();
// GET: RestCall
public async Task<ActionResult> RunAsync(string a, string b)
{
using (var handler = new HttpClientHandler { UseDefaultCredentials = true })
using (var client = new HttpClient(handler))
{
var byteArray = Encoding.ASCII.GetBytes("username:password");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
client.BaseAddress = new Uri("XXX");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync("XXX");
if (response.IsSuccessStatusCode)
{
//Get the response
loginJsonString = await response.Content.ReadAsStringAsync();
result.loginJsonStringop = loginJsonString;
//Json deserialization
VehicleResponse vehicleobj = JsonConvert.DeserializeObject<VehicleResponse>(loginJsonString);
List<string> modelList = new List<string>();
List<string> descriptionList = new List<string>();
foreach (Vehicle veh in vehicleobj.Vehicles)
{
var model = veh.Model;
var Description = veh.Description;
modelList.Add(model);
var modellist = modelList;
descriptionList.Add(Description);
}
}
}
return RedirectToAction("Index", "HomeController",new { resultop =result });
}
}
Following is my HomeController.
public class HomeController : Controller
{
string a;
string b;
// GET: Home
public ActionResult Index(Result resultop)
{
RestCallController restcallController = new RestCallController();
restcallController.RunAsync(a,b);
resultop.loginJsonStringop = restcallController.loginJsonString;
return View(resultop);
}
}
This is my model class.
public class Result
{
public string loginJsonStringop { get; set; }
public string modelop { get; set; }
public string descriptionop { get; set; }
}
I want to pass value of loginJsonString, modelList,descriptionList to index() method in Home Controller and view that in index view. If you have any suggestions please help me.
We have TempData in MVC to pass the data from one controller to another. you can even refer the Answer.
In your first controller you can do something.
TempData["jsonData"] = ANY_OBJECT;
And then in you home controller you can get it.
var object = TempData["jsonData"];
Update
Temp Data Limitation to keep in mind
but there is a catch.. temp data will be available only first call to controller. if you redirect to home pass after your rest controller you will be able to get temp data in home controller, but if you did some redirection and then you directed to home, and tried to get temp data it will not work. if you need that, and think creating proper model, and passing it to home controller is a good solution.
UPDATE
you are trying to pass data using model then you can do something. --
public async Task<ActionResult> RunAsync(string a, string b)
{
...
...
...
Result obj = new Result();
obj.loginJsonStringop = "VALUE_OF_FIELD";
...
...
...
return RedirectToActtion("Index", "HomeController",new { resultop =result });
}
and then you home controller must recieve this model in Index action.
public class HomeController : Controller
{
public ActionResult Index(Result resultop)
{
// do whatever you want to do with your "resultop" instance of type "Result"
var value = resultop.loginJsonStringop; // "VALUE_OF_FIELD"
return View();
}
}
Related
I have the following injection:
services.AddSingleton<HttpClientFabric>();
HttpClientFabric is something like a bunch of HttpClients, see:
public class HttpClientFabric
{
public HttpClientFabric(IOptions<MyOptions> myOptions)
{
HttpClientOne = new HttpClient();
HttpClientTwo = new HttpClient();
}
public HttpClient HttpClientOne { get; }
public HttpClient HistoryHttpClient { get; }
I use it in a controller for example. The code is about like:
[Route(....)]
public async Task<IActionResult> MyAction(string importantParam) {
var someParam = listOfImportantParams.FirstOrDefault(x => x.Name == importantParam);
HttpClientFabric.HttpClientOne.BaseAddress = _myOptions.Value.BaseUrl1;
if (someParam != null) {
HttpClientFabric.HttpClientOne.BaseAddress = someParam.NewBaseUrl;
}
var content = ...;
string uri = ...
var res = await HttpClientFabric.HttpClientOne.PostAsync(uri, content);
... and continue ... but here it's not important
}
So, the question is if two or more users made a request simultaneously would I have a mess with the base URLs?
I am trying to get the list of employees using Web API Get method in C# MVC and display in the view. But my list is coming null. I am not sure what i am missing. I am referring to this resource http://www.tutorialsteacher.com/webapi/consume-web-api-get-method-in-aspnet-mvc
Home Controller :
namespace Sample.Controllers
{
public class HomeController : Controller
{
private readonly EmployeeDBEntities _db = new EmployeeDBEntities();
public ActionResult Index()
{
IEnumerable<Employee> employees = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:62141/api/");
//HTTP GET
var responseTask = client.GetAsync("employee");
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsAsync<IList<Employee>>();
readTask.Wait();
employees = readTask.Result;
}
else //web api sent error response
{
//log response status here..
employees = Enumerable.Empty<Employee>();
ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
}
}
return View(employees);
}
}
}
Employee API Controller :
namespace Sample.Controllers
{
public class EmployeeController : ApiController
{
public IHttpActionResult GetAllEmployees()
{
IList<Employee> employees = null;
using (var ctx = new EmployeeDBEntities())
{
employees = ctx.Employees.ToList<Employee>();
}
if (employees.Count == 0)
{
return NotFound();
}
return Ok(employees);
}
}
You first should check the status code on you response.
If it is NotFound then there was no results (the way your code is done).
But your problem may be related to the fact that the result of ctx.Employees.ToList<Employee>(); is being disposed and terminated before the response is completed, but even that would give a DisposedException.
You should consider adding You database context instance object in a IoC container with transient lifetime, and inject does dependencies to the controller constructor, because the request does not end when the action method ends.
The ValidateMinMaxListCountAttribute validation attribute works in my unit test, but does not when used in WebAPI framework?
For example inside the unit test the "isValid" returns true, yet in the controller it fails. I'm guessing some kind of serialization issue?
Anyone have any ideas?
[TestCategory("ServiceTests")]
[TestMethod]
public void CallServiceCalc()
{
var client = new RestClient();
client.BaseUrl = new Uri("https://localhost:44379");
client.Authenticator = new HttpBasicAuthenticator("eric.schneider", "password");
var request = new RestRequest();
request.Resource = "api/Calculation/Calculate";
CoralRequest coralReq = new CoralRequest();
coralReq.ModelId = 1;
coralReq.ModelName = "2018";
coralReq.BasePlan = new BeneifitsPlanInputs();
coralReq.Plans.Add(new BeneifitsPlanInputs());
request.AddBody(coralReq);
ValidateMinMaxListCountAttribute va = new ValidateMinMaxListCountAttribute(1, 999);
bool isValid = va.IsValid(coralReq.Plans);
IRestResponse response = client.Execute(request);
Assert.IsTrue(response.StatusCode == System.Net.HttpStatusCode.OK, "Should not be ok");
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class ValidateMinMaxListCountAttribute : ValidationAttribute
{
public ValidateMinMaxListCountAttribute(int minimum, int maximum)
{
this.MinimumCount = minimum;
this.MaximumCount = maximum;
}
public int MinimumCount { get; set; }
public int MaximumCount { get; set; }
public override bool IsValid(object value)
{
var list = value as ICollection;
if (list != null)
{
if (list.Count > MaximumCount) { return false; }
if (list.Count < MinimumCount) { return false; }
return true;
}
return false;
}
}
public class CoralRequest
{
public CoralRequest()
{
this.Plans = new List<BeneifitsPlanInputs>();
}
/// <summary>
///
/// </summary>
[ValidateMinMaxListCount(1, 99, ErrorMessage = "Must have between 1 and 99 plans")]
public IList<BeneifitsPlanInputs> Plans { get; set; }
}
Based on one of your other questions, which seems to be related, you show that the controller action looks like...
[HttpGet("{mock}")]
public ActionResult<CoralResult> CalculateMock(CoralRequest mock)
While in the test, a GET request is being made, GET requests do not have a BODY, and yet you add one to the request. Meaning that most likely the model is not being populated/bind to correctly on the server
This looks like a classic XY problem
That action should most likely be a POST request if you want to get the BODY of the request, and the action should be refactored to explicitly state where the data should be attained from.
[Route("api/[controller]")]
public class CalculationController: Controller {
//POST api/Calculation/Calculate
[HttpPost("[action]")]
public ActionResult<CoralResult> Calculate([FromBody]CoralRequest model) {
if(ModelState.IsValid) {
CoralResult result = new CoralResult();
//...do something with model and populate result.
return result;
}
return BadRequest(ModelState);
}
}
Which should now match more closely to what was being attempted in the integration test
[TestCategory("ServiceTests")]
[TestMethod]
public void CallServiceCalc() {
var client = new RestClient();
client.BaseUrl = new Uri("https://localhost:44379");
client.Authenticator = new HttpBasicAuthenticator("eric.schneider", "password");
var request = new RestRequest(Method.POST); //<-- POST request
request.Resource = "api/Calculation/Calculate";
request.AddHeader("content-type", "application/json");
CoralRequest coralReq = new CoralRequest();
coralReq.ModelId = 1;
coralReq.ModelName = "2018";
coralReq.BasePlan = new BeneifitsPlanInputs();
coralReq.Plans.Add(new BeneifitsPlanInputs());
request.AddJsonBody(coralReq); //<-- adding data as JSON to body of request
IRestResponse response = client.Execute(request);
Assert.IsTrue(response.StatusCode == System.Net.HttpStatusCode.OK, "Should be HttpStatusCode.OK");
}
The model binder should now be able to validate the model after binding it and passing it to the action.
Reference Model Binding in ASP.NET Core
i'm using ASP MVC 5. I have an action in a controller that return a json object:
[HttpGet]
public JsonResult GetUsers()
{
return Json(....., JsonRequestBehavior.AllowGet);
}
Now i want to use the JSON.Net library and i see that in ASP MVC 5 is yet present. In effect i can write
using Newtonsoft.Json;
without import the library from NuGet.
Now i've tried to write:
public JsonResult GetUsers()
{
return JsonConvert.SerializeObject(....);
}
But i have an error during compilation: I cann't convert the return type string to JsonResult.
How can i use the Json.NET inside an action? What is the correct return type of an action?
I'd prefer to create an object extension that results in a custom ActionResult as it can be applied inline to any object when returning it
The bellow extension make use of Newtonsoft Nuget to serialize objects ignoring null properties
public static class NewtonsoftJsonExtensions
{
public static ActionResult ToJsonResult(this object obj)
{
var content = new ContentResult();
content.Content = JsonConvert.SerializeObject(obj, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
content.ContentType = "application/json";
return content;
}
}
The bellow example demonstrate how to use the extension.
public ActionResult someRoute()
{
//Create any type of object and populate
var myReturnObj = someObj;
return myReturnObj.ToJsonResult();
}
Enjoy.
You can use ContentResult instead like this:
return Content(JsonConvert.SerializeObject(...), "application/json");
public string GetAccount()
{
Account account = new Account
{
Email = "james#example.com",
Active = true,
CreatedDate = new DateTime(2013, 1, 20, 0, 0, 0, DateTimeKind.Utc),
Roles = new List<string>
{
"User",
"Admin"
}
};
string json = JsonConvert.SerializeObject(account, Formatting.Indented);
return json;
}
or
public ActionResult Movies()
{
var movies = new List<object>();
movies.Add(new { Title = "Ghostbusters", Genre = "Comedy", Year = 1984 });
movies.Add(new { Title = "Gone with Wind", Genre = "Drama", Year = 1939 });
movies.Add(new { Title = "Star Wars", Genre = "Science Fiction", Year = 1977 });
return Json(movies, JsonRequestBehavior.AllowGet);
}
You basically need to write a custom ActionResult that is indicated here in this post
[HttpGet]
public JsonResult GetUsers()
{
JObject someData = ...;
return new JSONNetResult(someData);
}
The JSONNetResult function is:
public class JSONNetResult: ActionResult
{
private readonly JObject _data;
public JSONNetResult(JObject data)
{
_data = data;
}
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
response.ContentType = "application/json";
response.Write(_data.ToString(Newtonsoft.Json.Formatting.None));
}
}
You might want to consider using IHttpActionResult since this will give you the benefit of serialization automatically (or you could do it yourself), but also allows you to control the returned error code in case errors, exceptions or other things happen in your function.
// GET: api/portfolio'
[HttpGet]
public IHttpActionResult Get()
{
List<string> somethings = DataStore.GetSomeThings();
//Return list and return ok (HTTP 200)
return Ok(somethings);
}
I'm using the following approach to upload files through ASP.NET Web API controllers.
[System.Web.Http.HttpPost]
public HttpResponseMessage UploadFile()
{
HttpResponseMessage response;
try
{
int id = 0;
int? qId = null;
if (int.TryParse(HttpContext.Current.Request.Form["id"], out id))
{
qId = id;
}
var file = HttpContext.Current.Request.Files[0];
int filePursuitId = bl.UploadFile(qId, file);
}
catch (Exception ex)
{
}
return response;
}
In my unit tests I've created an HTTPContext class manually before calling the UploadFile action:
var request = new HttpRequest("", "http://localhost", "");
var context = new HttpContext(request, new HttpResponse(new StringWriter()));
HttpContext.Current = context;
response = controller.UploadFile();
Unfortunately, I wasn't able to add custom values to the Form collection, since it's read-only. Also I couldn't change the Files collection.
Is there any way to add custom values to the Form and Files properties of the Request to add needed data (id and file content) during the unit test?
Use some mocking framework like Moq instead. Create a mock HttpRequestBase and mock HttpContextBase with whatever data you need and set them on the controller.
using Moq;
using NUnit.Framework;
using SharpTestsEx;
namespace StackOverflowExample.Moq
{
public class MyController : Controller
{
public string UploadFile()
{
return Request.Form["id"];
}
}
[TestFixture]
public class WebApiTests
{
[Test]
public void Should_return_form_data()
{
//arrange
var formData = new NameValueCollection {{"id", "test"}};
var request = new Mock<HttpRequestBase>();
request.SetupGet(r => r.Form).Returns(formData);
var context = new Mock<HttpContextBase>();
context.SetupGet(c => c.Request).Returns(request.Object);
var myController = new MyController();
myController.ControllerContext = new ControllerContext(context.Object, new RouteData(), myController);
//act
var result = myController.UploadFile();
//assert
result.Should().Be.EqualTo(formData["id"]);
}
}
}
Since you have no control over those classes why not wrap/abstract the functionality behind one do control
IRequestService request;
[HttpPost]
public HttpResponseMessage UploadFile() {
HttpResponseMessage response;
try {
int id = 0;
int? qId = null;
if (int.TryParse(request.GetFormValue("id"), out id)) {
qId = id;
}
var file = request.GetFile(0);
int filePursuitId = bl.UploadFile(qId, file);
} catch (Exception ex) {
//...
}
return response;
}
Where request is one of your custom defined types IRequestService
public interface IRequestService {
string GetFormValue(string key);
HttpPostedFileBase GetFile(int index);
//...other functionality you may need to abstract
}
and can be implemented like this to be injected into your controller
public class RequestService : IRequestService {
public string GetFormValue(string key) {
return HttpContext.Current.Request.Form[key];
}
public HttpPostedFileBase GetFile(int index) {
return new HttpPostedFileWrapper(HttpContext.Current.Request.Files[index]);
}
}
in your unit test
var requestMock = new Mock<IRequestService>();
//you then setup the mock to return your fake data
//...
//and then inject it into your controller
var controller = new MyController(requestMock.Object);
//Act
response = controller.UploadFile();