I am developing a web app that has a cloud server (nodeJS) and a local server (C#) to interface the serial port of the PC. The web page whose origin is the cloud server makes requests to the local server and gets this error
Access to fetch at 'http://localhost:3100/connection' from origin 'http://cloud.tissuelabs.com' has been blocked by CORS policy: The request client is not a secure context and the resource is in more-private address space `local`
I tried adding headers to the request
'headers': {'Access-Control-Allow-Origin': '*'}
but it doesn`t solve my problem. I solved this problem in python using CORS libraries, but I still want to solve this problem in C# (because of performance). This is my server in C#
private void InitializeServer()
{
myServer = new Thread(Server);
myServer.Start(this);
}
private void Server(Object _obj)
{
Route.Add((req, props) => req.Url.LocalPath.ToLower().EndsWith("connection"),
(req, res, args) =>
{
if (req.HttpMethod == "GET")
{
Regex rx = new Regex(#"port=(?<word>\w+)",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
MatchCollection matches = rx.Matches(req.Url.Query);
if (matches.Count > 0)
{
bool on = true;
bool printing = true;
WriteLog($"GET {req.Url.LocalPath + req.Url.Query}");
WriteLog($"{matches[0].Groups["word"].Value}");
string output = "{" + $"'on':{on}, 'printing':{printing}, 'queue': {10}" + "}";
res.AsText(output);
}
else
{
WriteLog($"GET {req.Url.LocalPath}");
string[] ports = SerialPort.GetPortNames();
string output = "{'ports':[";
foreach (string port in ports)
{
output += "{" + $"'port':'{port}', 'name':'{port}'" + "}";
}
output += "]}";
res.AsText(output);
}
}
else if (req.HttpMethod == "POST")
{
WriteLog("POST /connection");
Stream stream = req.InputStream;
StreamReader sr = new StreamReader(stream);
JsonSerializer serializer = new JsonSerializer();
Connection con = (Connection)serializer.Deserialize(sr, typeof(Connection));
connectSerial(con.port);
res.AsText("{'ok': True}");
}
else if (req.HttpMethod == "DELETE")
{
WriteLog("DELETE /connection");
res.AsText("OK");
}
});
HttpServer.ListenAsync(3100, System.Threading.CancellationToken.None, Route.OnHttpRequestAsync)
.Wait();
}
When I add access control allow origin to header, it works on firefox, but not on Chrome
res.AddHeader("Access-Control-Allow-Origin", "*");
Is there any library I could use with SimpleHttp? I am also using CefSharp to render the webpage. Is there any way to configure chromium web browser to ignore CORS errors?
CORS problem should be solved in server side, there must be a keyword or something that you should set your "project configuration files"
I found
namespace WebService
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// New code
config.EnableCors();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
and
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors;
namespace WebService.Controllers
{
[EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")]
public class TestController : ApiController
{
// Controller methods not shown...
}
}
just quick googling, please check for further information : https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
The first one enables cache for all of your controllers whereas the second method is controller based which in this case allows core request that only comes from given origins, if you'd like to allow for all origins you should set "*" as value.
Related
My main question is:
What is the difference between self hosted service inside a console app and a windows service?
I wrote a Self-Host Web API Console application which provides a simple api. For that I used basically the MSDN exemple:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
public class HeartbeatController : ApiController
{
public HttpResponseMessage Get()
{
var jsonToSend = GetJsonHeartbeatStatus();
if (!string.IsNullOrEmpty(jsonToSend))
{
var response = this.Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(jsonToSend, Encoding.UTF8, "application/json");
return response;
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
private string GetJsonHeartbeatStatus()
{
var hs = new HeartbeatStatus();
hs.Toolname = "html Scraper";
hs.Heartbeat = DateTime.Now.ToString();
hs.Plant = "plant1";
hs.Department = "departmentA";
hs.Servername = Environment.MachineName;
return JsonConvert.SerializeObject(hs);
}
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
logger.Info("In OnStart");
var UserDomain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
var Port = "8377";
string baseAddress = string.Format("http://{0}.{1}:{2}", Environment.MachineName, UserDomain, Port);
var completeAddress = baseAddress + "/api/heartbeat";
try
{
host = WebApp.Start<Startup>(baseAddress);
HttpClient client = new HttpClient();
var response = client.GetAsync(completeAddress).Result;
logger.Info("Api address: {0}", completeAddress);
logger.Info("Service Host started #{0}", DateTime.Now.ToString());
}
catch (Exception ex)
{
logger.Info("{0}", ex.ToString());
}
finally
{
if (host != null)
{
host.Dispose();
}
}
}
Next Step was to write a Firewall inbound role to get access to the port.
Then I tested it on our Windows Server 2016 Standard.
-> Test passed in Postman on another machine!
Now as you already saw (in the code) I took the code to a Windows Service Application (user= Local System). I am logging in Windows Event and I have no error in starting the host (that's why I used the try catch).
-> Test with the browser on the server failed and also with Postman on a different machine.
I figured out that I have to reserve the path with netsh
I tried:
netsh http add urlacl url=http://+:8377/api/heartbeat user=everyone
netsh http add urlacl url=http://machineName.corp:8377/api/heartbeat/ user=everyone
Installed the Service application with my user (admin) and set up the urls
netsh http add urlacl url=http://+:8377/api/heartbeat user=myUser
netsh http add urlacl url=http://machineName.corp:8377/api/heartbeat/ user=myUser
-> Test with the browser on the server failed and also with Postman on a different machine.
At this point I could not find any solution why my api is not working.
Does anybody have any ideas?
-edit-
Console appöication:
C:\Windows\system32>netstat -na | find "8378"
TCP 0.0.0.0:8378 0.0.0.0:0 LISTENING
TCP [::]:8378 [::]:0 LISTENING
TCP [fe80::5505:852c:952e:74f%6]:8378 [fe80::5505:852c:952e:74f%6]:62555 ESTABLISHED
TCP [fe80::5505:852c:952e:74f%6]:62555 [fe80::5505:852c:952e:74f%6]:8378 ESTABLISHED
Windows Service application:
C:\Windows\system32>netstat -na | find "8377"
no response!
I'm having a problem with a end point that I created
[Route("api/pag_seguro/transactions/credit_card")]
public string DoTransactionWithCreditCard(string senderHash, string cardHash, ProductModels[] products)
{
bool isSandbox = true;
EnvironmentConfiguration.ChangeEnvironment(isSandbox);
// Instantiate a new checkout
CreditCardCheckout checkout = new CreditCardCheckout();
// Sets the payment mode
checkout.PaymentMode = PaymentMode.DEFAULT;
// Sets the receiver e-mail should will get paid
checkout.ReceiverEmail = "financeiro#proteste.org.br";
// Sets the currency
checkout.Currency = Currency.Brl;
// Add items
checkout.Items.Add(new Item("0001", "Garrafa Laranja Tupperware", 1, 130.98m));
// Sets a reference code for this checkout, it is useful to identify this payment in future notifications.
checkout.Reference = "REFPT0002";
// Sets shipping information.
checkout.Shipping = new Shipping();
checkout.Shipping.ShippingType = ShippingType.Sedex;
checkout.Shipping.Cost = 0.00m;
checkout.Shipping.Address = new Address(
"BRA",
"SP",
"Sao Paulo",
"Jardim Paulistano",
"01452002",
"Av. Brig. Faria Lima",
"1384",
"5o andar"
);
// Sets a credit card token. -- gerado em 06/03/2017
checkout.Token = cardHash;
//Sets the installments information
checkout.Installment = new Installment(1, 130.98m, 2);
// Sets credit card holder information.
checkout.Holder = new Holder(
"Holder Name",
new Phone("11", "56273440"),
new HolderDocument(Documents.GetDocumentByType("CPF"), "12345678909"),
"01/10/1980"
);
// Sets shipping information.
checkout.Billing = new Billing();
checkout.Billing.Address = new Address(
"BRA",
"SP",
"Sao Paulo",
"Jardim Paulistano",
"01452002",
"Av. Brig. Faria Lima",
"1384",
"5o andar"
);
// Sets your customer information.
// If you using SANDBOX you must use an email #sandbox.pagseguro.com.br
checkout.Sender = new Sender(
"Diogo Amaral",
"comprador#sandbox.pagseguro.com.br",
new Phone("21", "992947883")
);
checkout.Sender.Hash = senderHash;
SenderDocument senderCPF = new SenderDocument(Documents.GetDocumentByType("CPF"), "12345678909");
checkout.Sender.Documents.Add(senderCPF);
try
{
AccountCredentials credentials = PagSeguroConfiguration.Credentials(isSandbox);
Transaction result = TransactionService.CreateCheckout(credentials, checkout);
//return result.TransactionStatus.ToString();
return result.Code.ToString();
}
catch (PagSeguroServiceException exception)
{
string errorstr = "";
foreach (Uol.PagSeguro.Domain.ServiceError erro in exception.Errors)
{
errorstr += erro.ToString();
}
return exception.Message + " - code: " + exception.StatusCode.ToString() + " - errors: " + exception.Errors.ToString() + " - errorstr: " + errorstr;
}
}
What is happening is that when I try to send a POST to this endpoint it doesn't work, it only accepts GET. What should I have to do to this become a POST endpoint?
I'm new on it, please help me guys. Thank you!
Now my code looks like this:
[HttpPost]
[Route("api/pag_seguro/transactions/credit_card")]
public string DoTransactionWithCreditCard(string senderHash, string cardHash, ProductModels[] products)
{
bool isSandbox = true;
EnvironmentConfiguration.ChangeEnvironment(isSandbox);
// Instantiate a new checkout
CreditCardCheckout checkout = new CreditCardCheckout();
...
}
But in console I still receiving 404 Not found error in Chrome console:
Request URL:http://localhost:40379/api/pag_seguro/transactions/credit_card
Request Method:POST
Status Code:404 Not Found
Add [HttpPost]:
[HttpPost]
[Route("api/pag_seguro/transactions/credit_card")]
public string DoTransactionWithCreditCard(string senderHash, string cardHash, ProductModels[] products)
Also make sure your RouteConfig contains routes.MapMvcAttributeRoutes():
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
//Other stuff
routes.MapMvcAttributeRoutes(); //make sure this is there
}
}
Add the [HttpPost] attribute to tell Web API it should accept the POST verb.
1) Go to App_Start directory in your project and modify file for Web Api configuration called WebApiConfig.css (add line config.MapHttpAttributeRoutes(); in order to turn on Route attribute)
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
2) add attribute [Post] before your WebAPI method.
You should define Request entity something like:
public class PayRequest {
public string senderHash;
public string cardHash;
public ProductModels[] products;
}
Instead fields you can define properties.
and you method should look like:
[HttpPost]
[Route("api/pag_seguro/transactions/credit_card")]
public string DoTransactionWithCreditCard(PayRequest request)
{
// ...
return "ok";
}
I'm trying out the Signal R and built a server dll (windows service library/c#) that runs as a Windows Services. I have build also a client application (asp.net web application) to communicate with the server.
But i'm getting always the error(Firefox) "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%5D&_=1482829095207. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)."
Chrome error "
Failed to load resource: the server responded with a status of 400 (Bad Request)"
XMLHttpRequest cannot load http://localhost:8080/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%5D&_=1482830200155. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:50259' is therefore not allowed access. The response had HTTP status code 400.
Note: Edge and also IE gives me errors
I have read almost every post about this subject on Stackoverflow, but non of these solutions seems to work.
The code i'm using for the server side:
namespace SignalRService
{
public class StartupConfiguration
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true,
EnableJSONP = true,
};
map.RunSignalR(hubConfiguration);
});
}
}
}
Services.cs
public void StartService()
{
LogMessage("SignalRService started", true);
Running = true;
WebApp.Start<StartupConfiguration>(ConfigurationManager.AppSettings["SignalRServerUrl"]);
}
EnvironmentSettings.config:
<add key="SignalRServerUrl" value="http://localhost:8080"/>
Hubs.cs
namespace SignalRService.Hubs
{
[HubName("TestHub")]
public class TestHub: Hub
{
public static Dictionary<string, List<HubClient>> clients = new Dictionary<string, List<HubClient>>();
[HubMethodName("Subscribe")]
public async Task Subscribe(string Id)
{...... }}
ClientSide (Javascript/Jquery)
var signalrHubConnection;
var signalrHubConnectionProxy;
var signalRServerUrl = "http://localhost:8080";
var currentTimeout;
var count = 0;
var startSignalRConnection = function () {
console.log("Start");
signalrHubConnection = $.hubConnection(signalRServerUrl);
console.log("Running");
signalrHubConnection.logging = true;
signalrHubConnectionProxy = signalrHubConnection.createHubProxy('TestHub');
console.log("--Subscribe starting");
signalrHubConnection.start()
.done(function () {
signalrHubConnectionProxy.invoke('Subscribe', Id.toString());
console.log("Subscribe ending");
})
.fail(function (test) {
if (count < 5) {
console.log(test.toString());
clearTimeout(currentTimeout);
currentTimeout = setTimeout(function () {
count++;
startSignalRConnection();
}, 300000); // retry after 5 minutes
}
}
);
signalrHubConnectionProxy.on('IncomingMessage',
function (message) {
console.log("Message = " + message.toString());
}
);
};
Test.aspx
<script src="https://code.jquery.com/jquery-3.1.1.min.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.1.min.js"></script>
Did I something wrong?
The error implied that the SignalR url is different from the requesting url (origin). So, SignalR is on localhost, but your main website (the site that holds the client side example) obviously is accessed using "localhost".
Maybe you're accessing it using an IP (eg http://127.0.0.1/) or your PC name (eg http://badassPC/), whereas they must match under the default SignalR setting. I am pretty certain it doesn't matter if the port is different, and also doesn't matter if they are on the same domain (eg www.mysite.com and signalr.mysite.com)
Note there is a workaround that I wouldn't recommend unless you really really know what you're doing as there is a quite serious security risk otherwise: https://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client#crossdomain
Yet another fiddler can't get it to capture post.
Similar to this SO Post I have spent two hours now reading and trying different solution yet none of them allow me to see my fiddler web api traffic.
As a side note my code is working I am just focused on getting fiddler to show me the api calls.
I will describe my setup then what I have tried.
My Web API is a separate MVC 6, EF 7 project running on port 63381
http://localhost:63381/
My ASP.NET MVC 5 web client project is running on port: 59722
http://localhost:59722/
A typical action controller in the mvc client:
//Controller CTOR
public ClientController()
{
client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:63381/api/MyApi");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
//Action within ClientController
public async Task<JsonResult> AddNewSubCategory()
{
HttpResponseMessage responseMessage = await client.PostAsJsonAsync(url2, content);
if (responseMessage.IsSuccessStatusCode)
{
return Json("[{Update Success}]", JsonRequestBehavior.AllowGet);
}
return Json("[{Error Updating}]", JsonRequestBehavior.AllowGet);
}
}
Added the block to 32 & 62 machine.config. Restarted visual studio did NOT restart machine or any other service. This did not work.
Added the block to the client web.config and this didn't work.
Changed localhost to machinename:port
Specifically I changed http://localhost:63381/api/MyApi to http://gpgvm-pc:63381/api/MyApi
Modified Global.asax with:
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
Fiddler custom rules
Reverse proxy
Set fiddler listening on a different port.
At this point I surrender. It seems to me #1 should work to capture everything but I am obviously still doing something wrong because I can get fiddler to capture one or the other but NOT the client calling off to the client???
Update:
My machine locked and after reboot I started seeing the api calls so this issue was something with my machine. So sorry to bother.
The problem is most likely that you are using localhost which are handled in a special way.
Try using machine name or your ip instead (do not use 127.0.0.1).
The documentation have information about this as well:
http://docs.telerik.com/fiddler/Observe-Traffic/Troubleshooting/NoTrafficToLocalhost
If you try to hit specific action in api then use that code in webapi config
public static void Register(HttpConfiguration config)
{
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional });
config.Routes.MapHttpRoute("API Default", "api/{controller}/{action}/{id}",
new { id = RouteParameter.Optional });
}
This code where u call your api.
public ActionResult ClientController(model content)
{
try
{
HttpClient client = new HttpClient("http://localhost:63381/");
client.BaseAddress = new Uri();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.PostAsJsonAsync("api/MyApi/url2", content).Result;
if (response.IsSuccessStatusCode)
{
return Json(new { code = 0, message = "Success" });
}
else
{
return Json(new { code = -1, message = "Failed" });
}
}
catch (Exception ex)
{
int code = -2;
return Json(new { code = code, message = "Failed" });
}
}
}
I have a WP7 game that uses RESTsharp to communicate with my MVC4 RESTful server, but I often have issues making requests that work and therefore I want to debug where it fails.
This is an example where the Constructor on my GameController is hit, but the Post method is not hit, and I don't understand why.
Client code:
public void JoinRandomGame()
{
client = new RestClient
{
CookieContainer = new CookieContainer(),
BaseUrl = "http://localhost:21688/api/",
};
client.Authenticator = GetAuth();
RestRequest request = new RestRequest(Method.POST)
{
RequestFormat = DataFormat.Json,
Resource = "game/"
};
client.PostAsync(request, (response, ds) =>
{});
}
Server code:
public void Post(int id)
{
if (ControllerContext.Request.Headers.Authorization == null)
{
//No auth
}
if (!loginManager.VerifyLogin(ControllerContext.Request.Headers.Authorization.Parameter))
{
//Failed login
}
string username;
string password;
LoginManager.DecodeBase64(ControllerContext.Request.Headers.Authorization.Parameter, out username, out password);
gameManager.JoinRandomGame(username);
}
My routes are like this
routes.MapHttpRoute(
name: "gameAPI",
routeTemplate: "api/game/{gameId}",
defaults: new
{
controller = "game",
gameId = RouteParameter.Optional
}
);
Another way is to add an event handler in Global.asax.cs to pick up the incoming request and then look at the route values in the VS debugger. Override the Init method as follows:
public override void Init()
{
base.Init();
this.AcquireRequestState += showRouteValues;
}
protected void showRouteValues(object sender, EventArgs e)
{
var context = HttpContext.Current;
if (context == null)
return;
var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(context));
}
Then set a breakpoint in showRouteValues and look at the contents of routeData.
Keep in mind that in a Web API project, the Http routes are in WebApiConfig.cs, not RouteConfig.cs.
RouteDebugger is good for figuring out which routes will/will not be hit.
http://nuget.org/packages/routedebugger
You can try ASP.NET Web API Route Debugger. It is written for Web Api. https://trocolate.wordpress.com/2013/02/06/introducing-asp-net-web-api-route-debugger/
http://nuget.org/packages/WebApiRouteDebugger/
There are more possibilities for testing the routes. You can try either manual testing or automated as part of unit tests.
Manual testing:
RouteDebugger
MVC API tracing
Automated testing:
MvcRouteTester.
Is GameController deriving from ApiController ?
Are you using WebApi ?
If not then i think the "/api/" is reserved for new WebApi feature. Try changing your routing and controller name to "gameapi"
If however you are using WebApi.
Then remove api from yor BaseUrl
client = new RestClient
{
CookieContainer = new CookieContainer(),
BaseUrl = "http://localhost:21688/",
};