Regarding mvc4 web api - asp.net-mvc

HEllo this is some piece of mvc4 webapi code can anyone over here explain me each line of code..I googled but didnt find any thing interesting
public HttpResponseMessage PostProduct(Product item)
{
item = repository.Add(item);
var response = Request.CreateResponse(HttpStatusCode.Created, item);
string uri = Url.RouteUrl("DefaultApi", new { id = item.Id });
response.Headers.Location = new Uri(uri);
return response;
}
I only understand that I am sending product item..and in return this web api returns me response of newly added product but I didnt understand this 2 lines in particular
string uri = Url.RouteUrl("DefaultApi", new { id = item.Id });
response.Headers.Location = new Uri(uri);

public HttpResponseMessage PostProduct(Product item)
{
//creates and adds an item to repository(db)
item = repository.Add(item);
//creates a new httpresponse
var response = Request.CreateResponse(HttpStatusCode.Created, item);
//creates new uri
string uri = Url.RouteUrl("DefaultApi", new { id = item.Id });
//set header for new uri
response.Headers.Location = new Uri(uri);
return response;
}
This lines will create a new RouteUrl -> basically a link for your response header.
My advice would be that you should start with official documentation from here: http://www.asp.net/web-api , it worked for me. There are many things to be researched here: http://geekswithblogs.net/JoshReuben/archive/2012/10/28/aspnet-webapi-rest-guidance.aspx
There are too many examples to be posted in this answer, that may help you.
· Response code: By default, the Web API framework sets the response
status code to 200 (OK). But according to the HTTP/1.1 protocol, when
a POST request results in the creation of a resource, the server
should reply with status 201 (Created). Non Get methods should return
HttpResponseMessage
· Location: When the server creates a resource, it should include the
URI of the new resource in the Location header of the response.
public HttpResponseMessage PostProduct(Product item)
{
item = repository.Add(item);
var response = Request.CreateResponse<Product>(HttpStatusCode.Created, item);
string uri = Url.Link("DefaultApi", new { id = item.Id });
response.Headers.Location = new Uri(uri);
return response;
}

public HttpResponseMessage PostProduct(Product item)
//this means that any post request to this controller will hit this action method
{
item = repository.Add(item);
//the posted data would be added to the already defined repository
var response = Request.CreateResponse(HttpStatusCode.Created, item);
//a responses is created with code 201. which means a new resource was created.
string uri = Url.RouteUrl("DefaultApi", new { id = item.Id });
//you get a new url which points to the route names DefaultAPI and provides a url parameter id(normally defined as optional)
response.Headers.Location = new Uri(uri);
//adds the created url to the headers to the response
return response;
//returns the response
}
normally as the standards go a POST request is used to create an entity. and the data to be put in that entity is sent with the request.
so the code here is creating the entity and then in the response sending back the url on which you can find the recently created entity. this is what any client would expect who is following the standards. Though this aint at all necessary.
so according to this you must have a GET action method that accepts the id as an parameter and returns the product corresponding to that id

Related

How to Call Web API from Another MVC Project with two Parameter one in header and second in body

I want to call api action from from mvc project but i have an issue API action have two parameter one in header and second in body.
You create a HttpClient object and set the header parameter
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:64189/api/");
//your header parameter name and value
client.DefaultRequestHeaders.Add("hdrname", "hdrvalue");
//HTTP GET
var responseTask = client.GetAsync("youraction?param1=abc"); //Action Name
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
// Use your class model to receive the data from the API
var readTask = result.Content.ReadAsAsync<IList<YourModel>>();
readTask.Wait();
var r = readTask.Result;
}
else //web api sent error response
{
//log response status here..
}
}

https://graph.microsoft.com/v1.0/users/ is returning only 100 records, I want to fetch all the record present in Azure AD

https://graph.microsoft.com/v1.0/users/ is returning only 100 records, I want to fetch all the record present in Azure AD.
I have tried with above API to but it always gives me 100 records and with top, I am able to fetch only 999 records. But I have more than 100k records and want to fetch at a time.
The call to https://graph.microsoft.com/v1.0/users/ returns a property called #odata.nextlink. Use #odata.nextlink to request more pages of user data.
I think it is not possible to fetch all users with one request but you could wirte a method getting all users for you. The following code is requesting the first 100 users. Afterwards it is calling the next 100 users until there is no more users.
It is only a work around. You should keep in mind that this function needs a long time to run
public async Task<List<GraphApiUser>> GetAllCloudUserAsync()
{
var query = "/users";
var response = await SendGraphApiRequest(HttpMethod.Get, query);
var data = JsonConvert.DeserializeObject<GetMultipleUserResponse>(await response.Content.ReadAsStringAsync());
var result = new List<GraphApiUser>();
result.AddRange(data.value);
var debugCounter = 1;
while (!string.IsNullOrEmpty(data.NextLink))
{
response = await SendGraphApiRequest(HttpMethod.Get, "/"+data.NextLink);
data = JsonConvert.DeserializeObject<GetMultipleUserResponse>(await response.Content.ReadAsStringAsync());
result.AddRange(data.value);
debugCounter++;
}
return result;
}
GetMultipleUserResponse-Class looks like that:
public class GetMultipleUserResponse
{
public List<GraphApiUser> value { get; set; }
[JsonProperty("odata.nextLink")]
public string NextLink { get; set; }
}
The GraphApiUser-Class looks diffrent from AD to AD because everyone is able to define own claims. Setting up this class belongs to you!
Sending a request can be done like this:
private async Task<HttpResponseMessage> SendGraphApiRequest(HttpMethod httpMethod, string query,
string json = "")
{
HttpClient http = new HttpClient();
var requestUri = "Your Ressource Id" + "Your Tenant" + "your query"+ "your api version";
HttpRequestMessage request = new HttpRequestMessage(httpMethod, requestUri);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", GetYourTokenHere());
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
string error = await response.Content.ReadAsStringAsync();
object formatted = JsonConvert.DeserializeObject(error);
Debug.WriteLine("Error Calling the Graph API: \n" +
JsonConvert.SerializeObject(formatted, Newtonsoft.Json.Formatting.Indented));
return null;
}
return response;
}

Graph REST AddMember to Group - Bad Request

I am attempting to add members to a group. I am able to list all groups in my org, get user by email, get all users and I can even remove a Member from a group but I cannot add one - The error returned is 400 Bad Request.
Here is the function which is the same function signature as those that work: (I do have the accesstoken, valid group id and a valid member id)
I have confirmed the body data looks correct at least as far as I can see from the example in the docs.
Not sure what else I can add to make things clearer, ask and I'll update
public async Task<string> AddGroupMember(string accessToken, string groupId, string memberId)
{
var status = string.Empty;
string endpoint = $"https://graph.microsoft.com/v1.0/groups/{groupId}/members/$ref";
string queryParameter = "";
// pass body data
var keyOdataId = "#odata.id";
var valueODataId = $"https://graph.microsoft.com/v1.0/directoryObjects/{memberId}";
var values = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>(keyOdataId, valueODataId)
};
var body = new FormUrlEncodedContent(values);
try
{
using(var client = new HttpClient())
{
using(var request = new HttpRequestMessage(HttpMethod.Post, endpoint + queryParameter))
{
request.Content = body;
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
using(var response = await client.SendAsync(request))
{
if (response.StatusCode == HttpStatusCode.NoContent)
status = "Member added to Group";
else
status = $"Unable to add Member to Group: {response.StatusCode}";
}
}
}
}
catch (Exception ex)
{
status = $"Error adding Member to Group: {ex.Message}";
}
return status;
}
Thanks for any help that anyone can offer - this is the last call I have to make then home free
Found the issue for any who care to know for the future:
var body = new FormUrl... my code was incorrect, what's needed is a simple json string changed to this UPDATED:
var jsonData = $#"{{ ""{keyOdataId}"": ""{valueODataId}"" }}";
var body = new StringContent(jsonData, Encoding.UTF8, "application/json");
I would normally put the values in a class but this is for proof of concept and the json key needs to look exactly like this #odata.id
Clarifying what is happening here:
The request body for this call should be JSON encoded (application/json). The FormUrlEncodedContent method returns your dictionary as Form encoded (application/x-www-form-urlencoded).
You can write the JSON by hand (like you have so far) but a better solution would be to leverage Json.NET. This will let you encode the dictionary in much the same way you were with FormUrlEncodedContent:
var values = new Dictionary<string, string>
{
{ keyOdataId, valueODataId}
};
var body = JsonConvert.SerializeObject(values);
If you're going to be doing a lot of work with Microsoft Graph, I would highly recommend switching to the Microsoft Graph .NET SDK.
You're method here would be far simpler using the SDK:
public async Task<string> AddGroupMember(string groupId, string memberId)
{
GraphServiceClient graphClient = AuthenticationHelper.GetAuthenticatedClient();
User userToAdd = new User { Id = memberId };
await graphClient.Groups[groupId].Members.References.Request().AddAsync(userToAdd);
}

View not updating after post with ASP.Net MVC

I'm trying to build a very simple website to display some test data being added & updated using asp.net mvc (with razor) but whenever data is posted to my Post method, my data is not being updated. I'm trying to get a unordered list (for now) to be updated the second a post is triggered.
I'm posting my data as JSON using the following code:
string jsonDeviceData = SerializeHelper.Serialize<IDeviceData>(deviceData,
ContentTypeEnum.Json, false);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(localServerUrl);
webRequest.Method = "POST";
webRequest.ContentType = "application/json"; //"application/x-www-form-urlencoded";
byte[] deviceDataBuffer = Encoding.UTF8.GetBytes(jsonDeviceData);
Task<Stream> requestTask = webRequest.GetRequestStreamAsync();
using (Stream requestStream = requestTask.Result)
{
requestStream.Write(deviceDataBuffer, 0, deviceDataBuffer.Length);
}
Task<WebResponse> responseTask = webRequest.GetResponseAsync();
using (StreamReader requestReader = new StreamReader(responseTask.Result
.GetResponseStream()))
{
string webResponse = requestReader.ReadToEnd();
Debug.WriteLine("Web Response: " + webResponse);
}
Below is the code I'm using in the POST method. Don't worry about the logic being so simplistic and probably horrible, but I'm just dabbling with this idea. Data will be stored in SQL Server database and I'll use EF if I decide to go further with this:
[HttpPost()]
public ActionResult Index(DeviceModel model)
{
if (ModelState.IsValid && model != null)
{
var deviceViewModelList = HttpContext.Application["DeviceList"]
as List<DeviceViewModel> ?? new List<DeviceViewModel>();
if (deviceViewModelList.All(m => !string.Equals(m.Name,
model.Name,
StringComparison.InvariantCultureIgnoreCase)))
{
deviceViewModelList.Add(new DeviceViewModel(model));
}
HttpContext.Application["DeviceList"] = deviceViewModelList;
var homePageViewModel = new HomePageViewModel
{
DeviceList = deviceViewModelList
};
return RedirectToAction("Index");
}
else
{
return View();
}
}
My model is passed correctly and everything works ok when the data is posted my page is not updated, even after calling RedirectToAction("Index");
The code below gets called the first time the page is loaded and after calling the RedirectToActio("Index"):
public ActionResult Index()
{
ViewBag.Title = "Test Server";
var deviceViewModelList = HttpContext.Application["DeviceList"]
as List<DeviceViewModel> ?? new List<DeviceViewModel>();
var homePageViewModel = new HomePageViewModel
{
DeviceList = deviceViewModelList
};
return View(homePageViewModel);
}
This is the code I have in my .cshtml page:
<ul>
#if (Model?.DeviceList != null)
{
foreach (var device in Model.DeviceList)
{
<li>#device.Name</li>
}
}
</ul>
If I check Fiddler, the data, in this case, the list is build correctly.
If I press F5 my data is displayed correctly.
I've read so many articles at this stage and I still haven't got a solution, one of them being View not updated after post and while I've tried ModelState.Clear(); and as you can see from my code I'm using #device.Name which is one of the suggestion. I'm not sure about the last one.
Another article I read was ASP NET MVC Post Redirect Get Pattern but again to no avail.
I'm obviously missing something.
Most articles/samples I've been looking at refer to posting via a Form and I know I'm posting, but is that the same as posting via a Form?
Also my page's viewModel is for my page and it contains a list of devices. Is that OK rather than passing the list of device as the viewmodel to the page? The reason I'm doing this is that I will want to access other lists at a later stage.
Has anyone got any suggestions?
Much appreciated.

ASP.NET MVC - Using cURL or similar to perform requests in application

I'm building an application in ASP.NET MVC (using C#) and I would like to know how I can perform calls like curl http://www.mywebsite.com/clients_list.xml inside my controller
Basically I would like to build a kind of REST API to perform actions such as show edit and delete, such as Twitter API.
But unfortunately until now I didn't find anything besides that cURL for windows on this website: http://curl.haxx.se/
So I don't know if is there any traditional way to retrieve this kind of call from URL with methods like post delete and put on the requests, etc...
I just would like to know an easy way to perform commands like curl inside my controller on my ASP.NET MVC Application.
UPDATE:
Hi so I managed to make GET Requests but now I'm having a serious problem in retrieve POST Request for example, I'm using the update status API from Twitter that in curl would work like this:
curl -u user:password -d "status=playing with cURL and the Twitter API" http://twitter.com/statuses/update.xml
but on my ASP.NET MVC application I'm doing like this inside my custom function:
string responseText = String.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://twitter.com/statuses/update.xml");
request.Method = "POST";
request.Credentials = new NetworkCredential("username", "password");
request.Headers.Add("status", "Tweeting from ASP.NET MVC C#");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
responseText = sr.ReadToEnd();
}
return responseText;
Now the problem is that this request is returning 403 Forbidden,
I really don't know why if it works perfectly on curl
:\
UPDATE:
I finally manage to get it working, but probably there's a way to make it cleaner and beautiful, as I'm new on C# I'll need more knowledge to do it, the way the POST params are passed makes me very confused because is a lot of code to just pass params.
Well, I've created a Gist - http://gist.github.com/215900 , so everybody feel free to revise it as you will. Thanks for your help çağdaş
also follow the code here:
public string TwitterCurl()
{
//PREVENT RESPONSE 417 - EXPECTATION FAILED
System.Net.ServicePointManager.Expect100Continue = false;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://twitter.com/statuses/update.xml");
request.Method = "POST";
request.Credentials = new NetworkCredential("twitterUsername", "twitterPassword");
//DECLARE POST PARAMS
string headerVars = String.Format("status={0}", "Tweeting from ASP.NET MVC C#");
request.ContentLength = headerVars.Length;
//SEND INFORMATION
using (StreamWriter streamWriter = new StreamWriter(request.GetRequestStream(), ASCIIEncoding.ASCII))
{
streamWriter.Write(headerVars);
streamWriter.Close();
}
//RETRIEVE RESPONSE
string responseText = String.Empty;
using (StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream()))
{
responseText = sr.ReadToEnd();
}
return responseText;
/*
//I'M NOT SURE WHAT THIS IS FOR
request.Timeout = 500000;
request.ContentType = "application/x-www-form-urlencoded";
request.UserAgent = "Custom Twitter Agent";
#if USE_PROXY
request.Proxy = new WebProxy("http://localhost:3000", false);
#endif
*/
}
Try using Microsoft.Http.HttpClient. This is what your request would look like
var client = new HttpClient();
client.DefaultHeaders.Authorization = Credential.CreateBasic("username","password");
var form = new HttpUrlEncodedForm();
form.Add("status","Test tweet using Microsoft.Http.HttpClient");
var content = form.CreateHttpContent();
var resp = client.Post("http://www.twitter.com/statuses/update.xml", content);
string result = resp.Content.ReadAsString();
You can find this library and its source included in the WCF REST Starter kit Preview 2, however it can be used independently of the rest of the stuff in there.
P.S. I tested this code on my twitter account and it works.
Example code using HttpWebRequest and HttpWebResponse :
public string GetResponseText(string url) {
string responseText = String.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream())) {
responseText = sr.ReadToEnd();
}
return responseText;
}
To POST data :
public string GetResponseText(string url, string postData) {
string responseText = String.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentLength = postData.Length;
using (StreamWriter sw = new StreamWriter(request.GetRequestStream())) {
sw.Write(postData);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream())) {
responseText = sr.ReadToEnd();
}
return responseText;
}
This is the single line of code I use for calls to a RESTful API that returns JSON.
return ((dynamic) JsonConvert.DeserializeObject<ExpandoObject>(
new WebClient().DownloadString(
GetUri(surveyId))
)).data;
Notes
The Uri is generated off stage using the surveyId and credentials
The 'data' property is part of the de-serialized JSON object returned
by the SurveyGizmo API
The Complete Service
public static class SurveyGizmoService
{
public static string UserName { get { return WebConfigurationManager.AppSettings["SurveyGizmo.UserName"]; } }
public static string Password { get { return WebConfigurationManager.AppSettings["SurveyGizmo.Password"]; } }
public static string ApiUri { get { return WebConfigurationManager.AppSettings["SurveyGizmo.ApiUri"]; } }
public static string SurveyId { get { return WebConfigurationManager.AppSettings["SurveyGizmo.Survey"]; } }
public static dynamic GetSurvey(string surveyId = null)
{
return ((dynamic) JsonConvert.DeserializeObject<ExpandoObject>(
new WebClient().DownloadString(
GetUri(surveyId))
)).data;
}
private static Uri GetUri(string surveyId = null)
{
if (surveyId == null) surveyId = SurveyId;
return new UriBuilder(ApiUri)
{
Path = "/head/survey/" + surveyId,
Query = String.Format("user:pass={0}:{1}", UserName, Password)
}.Uri;
}
}
Look into the System.Net.WebClient class. It should offer the functionality you require. For finer grained control, you might find WebRequest to be more useful, but WebClient seems the best fit for your needs.

Resources