I am trying to save data to my Firebase database from C# using the REST api. I get 403 errors when I try to save the data (trying to save to a list). I am able to save data to this list from angular (using AngularFyre), but I get a 403 every time I try from the REST api. My database is setup with the default rules which currently allows reads and writes to everything and this appears to work as evidenced by the fact that I can save from Angular.
The url I'm posting to looks like this https://[mydb].firebaseio.com/subscriptions. Here's the code I'm using:
void SaveToFirebase<T>(T objectToSave, string url)
{
var request = WebRequest.Create(url);
request.Method = "PUT";
request.ContentType = "application/json";
var stream = request.GetRequestStream();
using (var streamWriter = new StreamWriter(stream))
{
var serializedData = jsonSerializer.Serialize(objectToSave, true);
streamWriter.Write(serializedData);
streamWriter.Close();
}
stream.Close();
using (var response = request.GetResponse())
{
ThrowIfHttpSaveRequestFailed(request, response);
}
}
I discovered that the problem was that I simply wasn't including .json in my url. So the URL that was giving me a 403 looked like this https://[mydb].firebaseio.com/subscriptions/id and it needed to look like this: ttps://[mydb].firebaseio.com/subscriptions/id.json. This fixed the 403 problem.
Related
There must be something wrong with my c# code. I am trying to download some Json from an Azure Blob. I can download the Json in Postman and from MS Edge however, using my code there are no apparent errors in the request but there is no content in the response. Presumably there is something wrong with my code.
async Task GetJson()
{
var request = new HttpRequestMessage
{
Method = new HttpMethod("GET"),
RequestUri = new Uri("https://xxx.blob.core.windows.net/trading/m5.json")
};
request.Headers.Add("Accept", "application/json");
request.SetBrowserRequestMode(BrowserRequestMode.NoCors);
var response = await http.SendAsync(request);
var json = await response.Content.ReadAsStringAsync();
}
This was asked on GitHub and apparently it is by design.
When you remove request.SetBrowserRequestMode(BrowserRequestMode.NoCors); line you will see the No 'Access-Control-Allow-Origin' header is present error.
Specifiying BrowserRequestMode.NoCors does not let you bypass the Browser security rules. It just simplifies the request headers.
Trying to use JWT Authentication for WP REST API using WordPressPCL API.
Managed to authenticate and publish both posts and pages to the WordPress server using WordPressPCL. In order to restrict access to only paying members I was planning to use MemberPress. I created a special category for the post and published them as such. The I set up a rule in MemberPress to give access to only to subscribers.
Tested access to the posts and can see the content from my Browser and all is fine with that.
The issue is that when I try to do the same using WordPressPCL although I am properly authorized from the JWT/WordPress perspective I don't have access to the content. It looks like MemberPress blocks an authorized user coming via WordPressPCL but allows access when coming via the web browser.
The same thing happen when I try to post pages as opposed to posts. I should also mention that I can download all posts metadata but not the content of each post which takes me to "You are unauthorized to view this page".
The code below retrieves all posts with a certain title and certain category but myPosts.Content.Rendered == "You are unauthorized to view this page" for all posts.
try
{
WordPressClient client = await GetClient(clientURL,userName,password);
if (await client.IsValidJWToken())
{
var posts = await client.Posts.GetAll();
var myPosts = posts.Where(p => p.Categories[0] == category && p.Title.Rendered == title);
}
...
I tried a similar thing without JWT. I can authenticate but cannot retrieve page content:
CookieContainer cc = new CookieContainer();
var request = (HttpWebRequest)WebRequest.Create(loginUri);
request.Proxy = null;
request.AllowAutoRedirect = false;
request.CookieContainer = cc;
request.Method = "post";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = requestData.Length;
using (Stream s = request.GetRequestStream())
s.Write(requestData, 0, requestData.Length);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
foreach (Cookie c in response.Cookies)
Console.WriteLine(c.Name + " = " + c.Value);
}
string newloginUri = "http://localhost/myWP/myPostforToday/";
HttpWebRequest newrequest = (HttpWebRequest)WebRequest.Create(newloginUri);
newrequest.Proxy = null;
newrequest.CookieContainer = cc;
using (HttpWebResponse newresponse = (HttpWebResponse)newrequest.GetResponse())
using (Stream resSteam = newresponse.GetResponseStream())
using (StreamReader sr = new StreamReader(resSteam))
File.WriteAllText(#"retrievedpage.html", sr.ReadToEnd());
I suspect that MemeberPress rules restrict the access but I couldn't find any solution. Some guidance on how to handle this ( with or without MemberPress involvement) would be really appreciated.
Change this
var posts = await client.Posts.GetAll();
to:
var posts = await client.Posts.GetAll().Result;
If you have Result() I think this will work and next original ;
var client = new WordPressClient("http://wordpress-domain.com/wp-json/");
client.AuthMethod = AuthMethod.JWT;
await client.RequestJWToken("user", "password");
return client;
But you use:
WordPressClient client = await GetClient(clientURL,userName,password);
I have an Angular 4 application which consumes an Asp.Net Web Api, and I want the Api to return a binary file. The Api route seems to be working correctly - I tested it using a rest console and the response is as expected. However, when trying to use the same route in the Angular app, the request sends but returns an error. I can see with the C# debugger that the request is executing completely and doesn't fail on the server. Here's the error in the JS console:
This error occurs on all browsers tested (Chrome, Firefox, IE, Edge, Safari).
Here's the server side code:
[Route("api/getfile")]
public IHttpActionResult GetFile()
{
byte[] file = <file generator code>;
System.Net.Http.HttpResponseMessage responseMessage = new System.Net.Http.HttpResponseMessage
{
Content = new System.Net.Http.StreamContent(new System.IO.MemoryStream(file))
};
responseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
responseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
responseMessage.Content.Headers.ContentDisposition.FileName = "file.pdf";
return this.ResponseMessage(responseMessage);
}
And here's the Angular code:
let headers = new Headers({
"Accept": "application/octet-stream",
"X-Requested-With": "XMLHttpRequest",
"Authorization": `Bearer ${token}`
});
let opts = new RequestOptions({headers = headers});
opts.responseType = ResponseContentType.Blob;
// Uses old #angular/http, not HttpClient
this.http
.get(`${apiUrl}/getfile`, opts)
.map(res => res.blob())
.catch(err => handleError(err));
EDIT: I tried using a plain XMLHttpRequest instead of Angular's Http service and it works. What do I need to do to get this to work with Angular?
EDIT 2: It works if I fetch an actual file on the file system that's accessible using the same host that the Angular app is running on. The Angular app is on localhost:8080, while the api is on a different port. If I expose a file on localhost:8080 (e.g., in the build folder) than I can fetch that file. This makes me wonder if it's a security issue, or maybe has to do with the headers or the way Web Api returns the binary data.
On your Api that will return your PDF
FileContentResult result;
if(!string.IsNullOrEmpty(fileName))
{
string absoluteFileName = Path.Combine(pathToFile, fileName);
byte[] fileContents = System.IO.File.ReadAllBytes(absoluteFileName);
result = new FileContentResult(fileContents, "application/pdf");
}
And then on Angular:
downloadFile(api: string) {
window.open(this.endPoint + api);
}
Try the old Way:
FileInfo fileInfo = New FileInfo(filePath)
Response.Clear()
Response.ClearHeaders()
Response.ClearContent()
Response.AddHeader("Content-Disposition", "attachment;filename=" + fileInfo.Name)
Response.AddHeader("Content-Type", "application/pdf")
Response.ContentType = "application/pdf"
Response.AddHeader("Content-Length", fileInfo.Length.ToString())
Response.TransmitFile(fileInfo.FullName)
Response.Flush()
Response.End()
This is for an image that I was keeping in a blob column in a db, but process should be similar. I ended up doing something like this back in Angular 4 (although this was 4.3+ which means HttpClient, not Http) to handle downloading files on clicking a button:
public downloadImage(id: number, imageName: string, imageType: string) {
this.http.get(urlToApiHere, { responseType: 'blob' }).subscribe((image: Blob) => {
if (isPlatformBrowser(this.platformId)) {
let a = window.document.createElement("a");
document.body.appendChild(a);
let blobUrl = window.URL.createObjectURL(image);
a.href = blobUrl;
a.download = imageName;
a.click();
window.URL.revokeObjectURL(blobUrl);
document.body.removeChild(a);
}
})
}
This API is .Net Core, but should be similar in .Net MVC, I believe:
[HttpGet]
public FileResult DisplayLineItemImage(int lineItemID)
{
using (var db = new Context())
{
var image = //retrieve blob binary, type, and filename here
if (image.Image == null)
{
//throw error
}
return File(image.Image, image.Type, image.Name);
}
}
The second answer by Crying Freeman, using Response directly, does work, but it bypasses Owin's processing and would mean having to manually implement things like CORS or anything else normally handled using CORS.
I found another solution, to use a custom formatter to allow returning a byte array from the controller method. This is also nicer because I don't need to set any headers manually, not even Content-Type.
I'm just a beginner on the .NET world and I've created a web api (.NET 4.5.2) and I'm using the annotation [Authorize] above my controllers like shown below:
[Authorize]
public class PhasesController : ApiController
{
private TestReportEntities db = new TestReportEntities();
// GET: api/Phases
public IQueryable<Phase> GetPhase()
{
return db.Phase;
}
}
I've already created my DB and I'm using the default tables that the web.api uses to manage the access, as you can see on this image:
My tables
I've already done a method to request to my web api, in another project/solution, it's working fine when I remove the annotation [Authorize] from my web api controllers.
this is an example about how I'm requesting my api:
public int GetCurrentIdPhase(int idProject)
{
int phaseId = -1;
WebRequest request = WebRequest.Create(string.Concat(URL, string.Format("api/phases/?idProject={0}", idProject)));
using (var resp = (HttpWebResponse)request.GetResponse())
{
using (var reader = new StreamReader(resp.GetResponseStream()))
{
string objText = reader.ReadToEnd();
var phase = JsonConvert.DeserializeObject<List<Phase>>(objText);
phaseId = phase[0].id;
}
}
if (phaseId != -1)
{
return phaseId;
}
else
{
throw new Exception("Phase not found");
}
}
At the end of the day my questions are:
How can I request a token to my api (POST - www.myApi/token) using the example above?
How can I use the token, once I've got it, on every request to my API?
if you can help me I would really appreciate it.
Thanks.
I've created a method to get the Token from my Web API, this is the method:
var request = (HttpWebRequest)WebRequest.Create(string.Concat(URL, "token"));
var postData = "grant_type=password";
postData += string.Format("&userName={0}", user);
postData += string.Format("&password={0}", pass);
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
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();
string objText = new StreamReader(response.GetResponseStream()).ReadToEnd();
var requestedToken = (JObject)JsonConvert.DeserializeObject(objText);
token = string.Concat(token, requestedToken["access_token"].Value<string>());
And to request something to my API all I need to do is just add the token on the header of all requests like shown on the line below:
request.Headers.Add(HttpRequestHeader.Authorization, getToke());
Hope it can help someone else who is beginning to work with .NET web API like me.
Regards.
Im assuming the "GetCurrentIdPhase" call is from an unrelated app with unrealted auth - if any auth.
The difficulty here is in using Authorize and the traidtional browser authentication flow. Here's an example of changing the pipeline a bit to use a different auth form for using console/desktop apps. You don't say where you are calling GetCurrentIdPhase from so I'll have to assume either a separate app. If its a web app and you are authenticated using the same tables, then you will have to share the token between them using for ex. the url blackice provided above.
If the app is a desktop/console/etc (not another app that the user had to auth against the same tables) then you can try this approach to change how auth is done to make it easier to access.
MVC WebAPI authentication from Windows Forms
I don't want to do anything fancy on Twitter except post to it via my site once a day. I have searched around a bit and there are all sorts of super-complex ways to do every little thing that Twitter does, but there seems to be little documentation on how to do the simplest thing, which is make a post!
Does anyone know how to do this? Or can you at least point me in the right direction? I don't need full wrappers or anything (http://apiwiki.twitter.com/Libraries#C/NET), just one simple function that will post to Twitter.
Thanks!
This is the easiest implementation ever. Up and running in under 2 minutes: Twitterizer
Its fairly simple; you just need to post an xml file to a web page using webrequest.create. This example is close (assumes you have the xml for the message in another place and just pass it into twitterxml variable as a string. The url might not be the right one; found it on this [page][1] which defines the interface
WebRequest req = null;
WebResponse rsp = null;
try
{
string twitterXML = "xml as string";
string uri = "http://twitter.com/statuses/update.format";
req = WebRequest.Create(uri);
//req.Proxy = WebProxy.GetDefaultProxy(); // Enable if using proxy
req.Method = "POST"; // Post method
req.ContentType = "text/xml"; // content type
// Wrap the request stream with a text-based writer
StreamWriter writer = new StreamWriter(req.GetRequestStream());
// Write the XML text into the stream
writer.WriteLine(twitterXML);
writer.Close();
// Send the data to the webserver
rsp = req.GetResponse();
}
[1]: http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses update
There are a couple different ways of doing this, they vary depending on the tools you want to use and have access to. Option 1 will work right out of the box, but the coding can be complicated. Option 3 you will have to download tools for, but once there installed and loaded you should be able to consume the twitter api very quickly.
Use WebRequest.Create to create/send messages to remote endpoints
Use WCF, create a mirror endpoint and access the twitter api using client only endpoint.
Use the WCF REST Starter Kit Preview 2, which has a new class called the HttpClient. I would have to recommend this technique if you can. Here is a great video Consuming a REST Twitter Feed in under 3 minutes.
Here is a sample of using the WCF REST Starter Kit's HttpClient:
public void CreateFriendship(string friend)
{
using (var client = new HttpClient())
{
var url = string.Format("http://www.twitter.com/friendships/create/{0}.xml?follow=true", friend);
client.Post(url)
.CheckForTwitterError()
.EnsureStatusIs(HttpStatusCode.OK);
}
}
Add a comment if you'd like more info about a particular method.
Update:
For Option #1 see this question: Remote HTTP Post with C#
There are a few ways of doing this, you can check out http://restfor.me/twitter and it will give you the code from RESTful documentation.
Essentially making any authenticated call you can follow this logic:
///
/// Executes an HTTP POST command and retrives the information.
/// This function will automatically include a "source" parameter if the "Source" property is set.
///
/// The URL to perform the POST operation
/// The username to use with the request
/// The password to use with the request
/// The data to post
/// The response of the request, or null if we got 404 or nothing.
protected string ExecutePostCommand(string url, string userName, string password, string data) {
WebRequest request = WebRequest.Create(url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password)) {
request.Credentials = new NetworkCredential(userName, password);
byte[] bytes = Encoding.UTF8.GetBytes(data);
request.ContentLength = bytes.Length;
using (Stream requestStream = request.GetRequestStream()) {
requestStream.Write(bytes, 0, bytes.Length);
using (WebResponse response = request.GetResponse()) {
using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
return reader.ReadToEnd();
}
}
}
}
return null;
}