I'm trying to dive into the RESTful web services world and have started with the following template:
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Test {
// TODO: Implement the collection resource that will contain the SampleItem instances
[WebGet(UriTemplate = ""), OperationContract]
public List<SampleItem> GetCollection() {
// TODO: Replace the current implementation to return a collection of SampleItem instances
return new List<SampleItem>() {new SampleItem() {Id = 1, StringValue = "Hello"}};
}
[WebInvoke(UriTemplate = "", Method = "POST"), OperationContract]
public SampleItem Create(SampleItem instance) {
// TODO: Add the new instance of SampleItem to the collection
throw new NotImplementedException();
}
[WebGet(UriTemplate = "{id}"), OperationContract]
public SampleItem Get(string id) {
// TODO: Return the instance of SampleItem with the given id
throw new NotImplementedException();
}
[WebInvoke(UriTemplate = "{id}", Method = "PUT"), OperationContract]
public SampleItem Update(string id, SampleItem instance) {
return new SampleItem {
Id = 99,
StringValue = "Done"
};
}
[WebInvoke(UriTemplate = "{id}", Method = "DELETE"), OperationContract]
public void Delete(string id) {
// TODO: Remove the instance of SampleItem with the given id from the collection
throw new NotImplementedException();
}
}
I am able to perform the GET operation but I am unable to perform PUT, POST or DELETE requests.
Can anyone explain me how to perform these operations and how to create the correct URLs?
Best regards
Alessandro
As far as I know, WebInvoke only supports GET and POST at this time. I use POST to perform PUT and DELETE action instead.
EDIT - Updated in response to your answer:
URL is "http://localhost/test/Test.svc/MethodName"
postData is the data you want to pass as a parameter.
In your case, it looks like you're trying to pass a type. Remember this is being posted in a URL. Break the values of the type into parameters.
Example: "http://localhost/test/Test.svc/Create?id=123456&stringValue=newSampleItem"
You'll need to change the Operation Contract to accept an int and a string instead of a SampleItem.
[WebInvoke(UriTemplate = "Create?id={x}&stringValue={y}", Method = "POST"), OperationContract]
public SampleItem Create(int id, string stringValue)
{
// Create and return the Sample Item.
}
Let me know how it goes.
Patrick.
Hi Alex, This is what I use to post to a Restful service...
// Create the request
WebRequest request;
request = WebRequest.Create(url + postData);
request.Method = "POST";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream();
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close();
// Process the response
Stream responseStream;
responseStream = request.GetResponse().GetResponseStream();
StreamReader objReader = new StreamReader(responseStream);
StringBuilder sb = new StringBuilder();
string sLine = "";
int i = 0;
while (sLine != null)
{
i++;
sLine = objReader.ReadLine();
sb.Append(sLine);
}
responseStream.Close();
string responseXML = sb.ToString()
Good Luck,
Patrick
Related
I saw below but it adds overhead of encode and decode strings.
C# - Send byte[] as part of json object using HttpWebRequest
I have a request object like below
[DataContract]
public class MyRequest
{
[DataMember]
public byte[] SampleByteArray { get; set; }
[DataMember]
public string UserId { get; set; }
}
I have below method that returns a byte[]
public byte[] SerializeToByteArray<T>(T input)
{
byte[] byteArray = null;
BinaryFormatter bf = new BinaryFormatter();
using (MemoryStream ms = new MemoryStream())
{
bf.Serialize(ms, input);
byteArray = ms.ToArray();
}
return byteArray;
}
I am creating my request object like below
MyRequest myRequest = new MyRequest();
myRequest.SampleByteArray = SerializeToByteArray(myDTO);
myRequest.UserId = "XXX";
I am making my HttpWebRequest object like below
HttpWebRequest request = WebRequest.CreateHttp(url);
request.ContentType = "application/json";
request.KeepAlive = false;
//100,000 milliseconds (100 seconds) need 10 minutes
request.Timeout = (int)TimeSpan.FromMinutes(10).TotalMilliseconds;
string stringfydata = Newtonsoft.Json.JsonConvert.SerializeObject(myRequest);
byte[] data = Encoding.UTF8.GetBytes(stringfydata);
request.ContentLength = data.Length;
var requestStream = request.GetRequestStream();
requestStream.Write(data, 0, data.Length);
requestStream.Close();
I am making WCF Rest call like below
string responseData;
using (WebResponse response = request.GetResponse())
{
using (var respStream = response.GetResponseStream())
{
using (var reader = new System.IO.StreamReader(respStream)
{
responseData = reader.ReadToEnd();
}
}
}
I am getting 400 Bad Request exception at
WebResponse response = request.GetResponse()
To test I changed my code like below and now atleast my service code gets hit and I am getting valid nice exception message which shows that my service is working.
MyRequest myRequest = new MyRequest();
myRequest.SampleByteArray = null;
myRequest.UserId = "XXX";
It looks like I am having issue sending byte[] to my service.
Can anyone please tell me how to send a byte[] as a property in a object that is converted into JSON format and calls a WCF Rest endpoint.
Please see below my service briefly.
[ServiceContract]
public interface IMyInterface
{
[Description("My test method")]
[OperationContract]
[WebInvoke(
UriTemplate = "mymethod",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json
)]
ServiceResponse GetResponse(MyRequest request);
}
public class MyInterface : IMyInterface
{
public ServiceResponse GetResponse(MyRequest request)
{
.... code goes here
}
}
Currently I am sending encrypted request to asp.net core controller. The following is the request body structure:
{
"body": "pEbXVvl1ue95eGQywK/q80cGHjYk+2VNPYEgnRgU+vI="
}
Before that I had implemented the filter IActionFilter so in OnActionExecuting(ActionExecutingContext context) where I decrypt the above mention request body(body key)
After decryption, I got the decrypted request body like below:
{
"Urno":"URN123456"
}
After decryption, I want to pass decrypted request (mentioned above "Urno":"URN123456") body to controller
I had tried to convert the string to byte than pass it to Request.body but no success:
public void OnActionExecuting(ActionExecutingContext context)
{
var request = context.HttpContext.Request;
request.EnableRewind();
request.Body.Position = 0;
using (var reader = new StreamReader(request.Body))
{
var bodyString = reader.ReadToEnd(); //{ "body": "pEbXVvl1ue95eGQywK/q80cGHjYk+2VNPYEgnRgU+vI="}
if (bodyString != "")
{
var data = JObject.Parse(bodyString);
var key = data.GetValue("body");
var keybytes = Encoding.UTF8.GetBytes("808080808080808011");
var iv = Encoding.UTF8.GetBytes("8080808080808080111");
var encrypted = Convert.FromBase64String(key.ToString());
var decriptedFromJavascript = DecryptStringFromBytes(encrypted, keybytes, iv); //{ "Urno":"URN123456"}
byte[] bytes = Encoding.ASCII.GetBytes(decriptedFromJavascript);
request.Body = new MemoryStream(bytes); // here i am trying to change request body
}
}
}
// controller
[HttpPost("[action]")]
public async Task<string> GetInvestorUrno(Urnoinvestor InfoReq){
}
// class
public class Urnoinvestor
{
public string Urno{ get; set; }
}
I want to change request body and pass the decrypted request to controller
For your scenario, IActionFilter would not work. Check this image:
The Model binding is run before ActionFilter which means no matter what you changed to the body, it would not change the model. You need to try the filter before Model binding like Resource filter.
Change to Resource filter
public class RequestBodyFilter : IResourceFilter
{
public void OnResourceExecuted(ResourceExecutedContext context)
{
//throw new NotImplementedException();
}
public void OnResourceExecuting(ResourceExecutingContext context)
{
var request = context.HttpContext.Request;
request.EnableRewind();
request.Body.Position = 0;
using (var reader = new StreamReader(request.Body))
{
var decriptedFromJavascript = "{ \"Urno\":\"URN123456\"}"; //{ "Urno":"URN123456"}
byte[] bytes = Encoding.ASCII.GetBytes(decriptedFromJavascript);
request.Body = new MemoryStream(bytes); // here i am trying to change request body
}
}
}
Since you are binding from body, you need to specify the action with [FromBody] as the suggestion from #Tony Abrams.
[HttpPost("[action]")]
[TypeFilter(typeof(RequestBodyFilter))]
public async Task<string> GetInvestorUrno([FromBody]Urnoinvestor InfoReq)
{
return InfoReq.Urno;
}
You don't have the parameter marked as from body, so it's not loading the data from the request body. Instead it's expecting it in the URI.
Try this instead:
[HttpPost("[action]")]
public async Task<string> GetInvestorUrno([FromBody]Urnoinvestor InfoReq){
}
I have an Asp Net Core 2.1 application with a REST controller like this:
[Produces("application/json")]
[Route("api/Test")]
public class TestController : Controller
{
// GET: api/Test
[HttpGet]
public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; }
// GET: api/Test/5
[HttpGet("{id}", Name = "Get")]
public string Get(int id) { return "value"; }
// POST: api/Test
[HttpPost]
public void Post([FromBody]string value)
{
//.. testing code..
}
// PUT: api/Test/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value) {}
// DELETE: api/ApiWithActions/5
[HttpDelete("{id}")]
public void Delete(int id) {}
}
I'm trying to use "System.Net.HttpWebRequest" object to make a POST request to Rest controller.
In my client application, I have a method that receives data as a string. The string content is a dynamic array of values such "param1=value1;param2=value2" (the number of elements is variable).
Can you help me to understand the correct way to send this data to the controller?
this is the code I'm trying to use in the client:
public static string PostWebApi(string postData)
{
var request = (HttpWebRequest)WebRequest.Create("http://localhost:64817/api/test");
// for example, assumes that postData value is "param1=value1;param2=value2"
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/json";
//request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream()) {
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
return responseString;
}
I'm using content type "application/json": if I try to use "application/x-www-form-urlencoded" I get "(415) Unsupported Media Type" error.
so... when I exec PostWebApi I receive a Null value parameter in the POST: api/Test method..
how can I receive the data I sent?
Thanks in advance.
you can use HTTPClient for this. it'll ease up the process for you.
public static string PostWebApi(string postData)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:64817/api/test");
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("value", postData)
});
var result = await client.PostAsync("/api/Membership/exists", content);
string resultContent = await result.Content.ReadAsStringAsync();
Console.WriteLine(resultContent);
}
}
Reference:- How to make HTTP POST web request
I have created the following restfull web service:
Interface
[ServiceContract]
public interface ISIGService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "GetTicket/")]
Ticket GetTicket(string user, string pwd);
}
Implementation
public class SIGService : ISIGService
{
public Ticket GetTicket(string user, string pwd)
{
return new Ticket()
{
Usuario = "xx",
UsuarioNombre = "xxx",
UsuarioId = "xxx"
};
}
Contract
[DataContract]
public class Ticket
{
[DataMember]
public int UsuarioId { get; set; }
[DataMember]
public string UsuarioNombre { get; set; }
[DataMember]
public string Usuario { get; set; }
}
I need to consume this service, from a web application, and get the typed object Ticket, I have included a service reference for this.
Server side code:
string urlService =
String.Format("http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'",
usuario, password);
var request = (HttpWebRequest)WebRequest.Create(urlService);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();
I put a text variable just to get something, sort of lost here.
I don't seem to get this object, could you give some pointers on this?
Most likely, you just need to change your URL from
http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'
to using the proper REST syntax (since you're using a REST service):
http://localhost:22343/SIGService.svc/GetTicket/{user}/{pwd}
Sample:
http://localhost:22343/SIGService.svc/GetTicket/daniel/topsecret
No ? or user= or single quotes necessary ....
With this, the value from {0} will be passed into the user parameter, and the value from {1} to the pwd parameter.
For consuming the service, I would recommend you check out the excellent RestSharp library which makes using your REST service a breeze.
Your code would look something like this:
// set up the REST Client
string baseServiceUrl = "http://localhost:22343/SIGService.svc";
RestClient client = new RestClient(baseServiceUrl);
// define the request
RestRequest request = new RestRequest();
request.Method = Method.GET;
request.RequestFormat = DataFormat.Xml;
request.Resource = "GetTicket/{user}/{pwd}";
request.AddParameter("user", "daniel", ParameterType.UrlSegment);
request.AddParameter("pwd", "top$ecret", ParameterType.UrlSegment);
// make the call and have it deserialize the XML result into a Ticket object
var result = client.Execute<Ticket>(request);
if (result.StatusCode == HttpStatusCode.OK)
{
Ticket ticket = result.Data;
}
Because Post requests to APIs need to run asynchronously on windows phone, I am struggling to create a lean easy to use library to interact with an API.
The issue is that people using the library will always need to supply a callback function.
Let's take a look at some pseudo code:
PostRequest Class to help me with POST requests:
class PostRequest
{
private Action<MemoryStream> Callback;
public PostRequest(string urlPath, string data, Action<MemoryStream> callback)
{
Callback = callback;
// Form the URI
UriBuilder fullUri = new UriBuilder(urlPath);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
// Initialize a new WebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fullUri.Uri);
request.Method = "POST";
// Set up the state object for the async request
DataUpdateState dataState = new DataUpdateState();
dataState.AsyncRequest = request;
// Start the asynchronous request
request.BeginGetResponse(new AsyncCallback(HandleResponse),
dataState);
}
private void HandleResponse(IAsyncResult asyncResult)
{
// Get the state information
DataUpdateState dataState = (DataUpdateState)asyncResult.AsyncState;
HttpWebRequest dataRequest = (HttpWebRequest)dataState.AsyncRequest;
// End the async request
dataState.AsyncResponse = (HttpWebResponse)dataRequest.EndGetResponse(asyncResult);
if (dataState.AsyncResponse.StatusCode.ToString() == "OK")
{
// Create a stream from the response
Stream response = dataState.AsyncResponse.GetResponseStream();
TextReader textReader = new StreamReader(response, true);
string jsonString = textReader.ReadToEnd();
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
// Send the stream through to the callback function
Callback(stream);
}
}
}
public class DataUpdateState
{
public HttpWebRequest AsyncRequest { get; set; }
public HttpWebResponse AsyncResponse { get; set; }
}
The API Access Object classes:
class APIAuthenticationCredentials
{
public String Username { get; set; }
public String Password { get; set; }
}
class APIAO
{
private String AuthUrl = "http://api.example.com/";
public static Auth Auth = new Auth();
//...
public static void Authenticate( String data, APIAuthenticationCredentials credentials, Action<MemoryStream> callback )
{
PostRequest request = new PostRequest(AuthURL, data, callback);
}
//...
}
You will notice I have to pass a callback function all the way through this so that once the data is returned by the HandleResponse method in my PostRequest class, the data is forwarded onto some controller that makes the screen do something with the data. At the moment, it's not ultra horrid to use:
private void DisplayData(MemoryStream stream)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Auth));
APIAO.Auth = (Auth)serializer.ReadObject(stream);
}
//...
APIAuthenticationCredentials credentials = new APIAuthenticationCredentials {
Username = "whatever",
Password = "whatever"
}
APIAO.Authenticate( credentials, DisplayData );
//...
The problem is I want to create some kind of repository style pattern... Let's say the API returned different json models, one call returned an array of products... the problem is that I want to create one lovely repository call eg:
IProductRepository productRepository = new ProductRepository();
productRepository.GetAll();
But I've gotta put some GOSH DARN callback function in it too and that means every repository method of any object type returned by the API is going to have this MemoryStream callback... and if I ever want to change that functionality, I've gotta update that stuff everywhere yo. :(
Has anyone seen a better way of doing this crap.
This is starting to become far too complex
--crying
A simpler answer using newer language constructs would be:
public static Task<string> GetData(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
return client.DownloadStringTaskAsync(fullUri.Uri);
}
In a 4.0 project you can use a TaskCompletionSource to translate a non-Task asynchronous model into a Task:
public static Task<string> GetData2(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
var tcs = new TaskCompletionSource<string>();
client.DownloadStringCompleted += (s, args) =>
{
if (args.Error != null)
tcs.TrySetException(args.Error);
else if (args.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(args.Result);
};
client.DownloadStringAsync(fullUri.Uri);
return tcs.Task;
}
The caller now has a Task<string> that represents the results of this asynchronous operation. They can wait on it synchronously and get the result using the Result property, they can add a callback that will execute when the operation finishes using ContinueWith, or they can await the task in an async method which, under the hood, will wire up the remainder of that method as a continuation of that task, but without creating a new method or even a new scope, i.e.
public static async Task Foo()
{
string result = await GetData("http://google.com", "");
Console.WriteLine(result);
}
This will start the asynchronous task, add a callback (or continuation) to that task so that when it runs it will continue executing code where it left off, at which point it will then write the results to the console and mark the Task that this method returns as completed, so that any continuations to this method will then execute (allowing for composition of async methods).