I'm trying register DocumentDB tracing with an existing listener. The code snippet below properly traces a single message to my expected listener but not the actual traces generated by the DocumentDB C# client. Am I missing something?
Snippet from Global.asax:
private static TraceSource DocDBSource;
private static TraceListener ExistingListener = new .....;
public void RegisterDocDBListener() {
DocDBSource = new TraceSource("DocDBTrace");
DocDBSource.Switch.Level = SourceLevels.Information;
DocDBSource.Listeners.Add(ExistingListener);
DocDBSource.TraceInformation("DocDB tracing initialized");
}
According to your description, I have checked the DefaultTrace from DocumentDB client library for .NET as follows:
For Client-side Logging with the .NET DocumentDB Client Library, you could configure the system.diagnostics configuration as follows to collect and persist documentdb log messages to a text file as follows:
<system.diagnostics>
<sources>
<source name="DocDBTrace">
<listeners>
<!--ConsoleTraceListener-->
<add name="configConsoleListener" type="System.Diagnostics.ConsoleTraceListener"/>
<!--TextWriterTraceListener-->
<add name="myListener"
type="System.Diagnostics.TextWriterTraceListener"
initializeData="TextWriterOutput.log" />
</listeners>
</source>
</sources>
<switches>
<add name="ClientSwitch" value="Warning"/>
</switches>
</system.diagnostics>
Note: The default Log Level is Information, you could change the ClientSwitch to your expected Log Level (Off, Error, Information, Verbose).
Result
Console Application
Web Application
Related
I am integrating mailchimp api in asp.net.
web.config:
<add key="APIKey" value="XXXX9dsfij4yZXXXXXXXXXX-XXXX" />
in code
using mailchimp;
IMailChimpManager manager = new MailChimpManager();
when I see what's in 'manager' object, it's null.
how do i get api key from web.config file?
According to:
https://github.com/brandonseydel/MailChimp.Net/blob/master/README.md You have two options here.
First, you can manually read API key from config:
using mailchimp;
using System.Configuration;
//Read API key from config
var apiKey= ConfigurationManager.AppSettings["APIKey"];
IMailChimpManager manager = new MailChimpManager(apiKey);
Second option is that you can change read key to MailChimpApiKey, so change
<add key="APIKey" value="XXXX9dsfij4yZXXXXXXXXXX-XXXX" />
to
<add key="MailChimpApiKey" value="XXXX9dsfij4yZXXXXXXXXXX-XXXX" />
In that case you don't need to pass API key:
using mailchimp;
IMailChimpManager manager = new MailChimpManager();
Browser console output:
XMLHttpRequest cannot load https://api.[...].com/[...]. Response to
preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost' is therefore not allowed access.
The response had HTTP status code 404.
I have an AngularJS application that is making calls to an API built in ASP.NET. Recently the backend team added versioning to the application, and for some reason, one of the API endpoints will no longer return 200 OK for the OPTIONS request (even though all the other API endpoints on that same server still return 200 OK). Always return 404 Not Found.
ASP.NET server seems to be using a WebApi.Cors package; no specific [HttpOptions] methods are being declared (all OPTIONS request are handled through the package); and the web.config feeds the CorsConfig with * for all of origin, headers, methods.
I've tried many of the solutions from Google results but nothing has worked.
Anyone face a similar issue and can give general guidance on what could be causing the issue, or how to potentially test for the problem, or attempt a solution?
[Edit:] Found solution.
Issue caused because "Version 1" of the API endpoint was dropped on that specific route. The first valid version on that endpoint was now "Version 2". So I added a blank Controller method to catch requests for "Version 1" (which only returns a blank string, nothing more), and this was sufficient to allow the OPTION request to resolve.
I think part of the issue here is the routing has changed:
Recently the backend team added versioning to the application
Things to check:
WebApi Configuration
Can you make sure that your configuration takes place as the first item in your Global.asax file:
void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configure(WebApiConfig.Register);
//...
}
Web API Routing
Has the versioniong been correctly configured inside the WebApiConfig?
public static void Register(HttpConfiguration config)
{
config.EnableCors(new EnableCorsAttribute("*", "*", "*");
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v2/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
}
In IIS 7.5 the only way I got CORS working was via the web.config and not through the Nuget package:
My web.config was as follows:
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<remove name="ExtensionLessUrlHandler-ISAPI-4.0_32bit" />
<remove name="ExtensionLessUrlHandler-ISAPI-4.0_64bit" />
<remove name="ExtensionLessUrlHandler-Integrated-4.0" />
<add name="ExtensionLessUrlHandler-ISAPI-4.0_32bit" path="*." verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
<add name="ExtensionLessUrlHandler-ISAPI-4.0_64bit" path="*." verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Found the solution. Posting it here for anyone else that has the problem in the future.
The API endpoint started with "version 2". There had been an earlier "version 1" that never made it to production, but it was dropped/discontinued because the signature would be completely changing. This was done because development teams had been using "version 1" up to that point, but since it wasn't going into production, logic dictated no longer having that version/endpoint.
For some reason, not having a "version 1" caused the OPTIONS to fail and return a 404 Not Found. My guess is because the required version header was not actually included with the OPTIONS pre-flight request, so it never resolved to a GET destination in the Controller.
Thus, you must have a version 1 reference, even if it's a placeholder that just returns a blank string.
Before:
[VersionedRoute("products", 2, Name = "GetProducts")]
[HttpGet]
public IHttpActionResult GetProducts([FromUri] GetProductsRequest request)
{
After:
[VersionedRoute("products", 1, Name = "GetProducts")]
[HttpGet]
public IHttpActionResult GetProducts()
{
return NotFound();
}
[VersionedRoute("products", 2, Name = "GetProducts_V2")]
[HttpGet]
public IHttpActionResult GetProducts_V2([FromUri] GetProductsRequest request)
{
I am trying to use the PayPal .NET RestApiSDK to store credit cards and take payments in their sandbox. I am using .NET 4.5 in an MVC project.
I followed the example code here:
https://developer.paypal.com/webapps/developer/docs/api/#store-a-credit-card
Initially, things were very easy. On day one, I was able to:
-take several payments
-store several cards
-look up sales
-refund sales
-store cards in the vault
(basically, everything in their example code)
Ever since day one (about a week), I have been getting an http 503 "Server Unavailable" error. Unless I changed something in my sleep, I am using the exact code that worked before.
I contacted PayPal support, and after several back and forth messages they have let me know that while they can't pinpoint an error in my code, the error must be on my side, because their servers are working fine.
What is really strange, is that I seem to be able to do anything that doesn't change data. For instance, I can call payments.List(). However, I can't call creditCard.Create() or payment.Create().
Also, the access token is being created just fine. The line tokenCredential.GetAccessToken() does not return any server error. When I debug the code, it has indeed returned with a proper token.
Question:
What could possibly be causing an http 503 error when I try to store a card or take a payment?
Here is some relevant code.
controller:
public JsonResult RunTestPayment()
{
string id = ConfigManager.Instance.GetProperties()["ClientID"];
string secret = ConfigManager.Instance.GetProperties()["ClientSecret"];
OAuthTokenCredential tokenCredential = new OAuthTokenCredential(id, secret);
string accessToken = tokenCredential.GetAccessToken();
PayPal.Api.Payments.Address billingAddress = new PayPal.Api.Payments.Address();
billingAddress.line1 = "52 N Main St";
billingAddress.city = "Johnstown";
billingAddress.country_code = "US";
billingAddress.postal_code = "43210";
billingAddress.state = "OH";
PayPal.Api.Payments.CreditCard creditCard = new PayPal.Api.Payments.CreditCard();
creditCard.number = "4417119669820331";
creditCard.type = "visa";
creditCard.expire_month = 11;
creditCard.expire_year = 2018;
creditCard.cvv2 = "874";
creditCard.first_name = "Joe";
creditCard.last_name = "Shopper";
creditCard.billing_address = billingAddress;
PayPal.Api.Payments.Details amountDetails = new PayPal.Api.Payments.Details();
amountDetails.subtotal = "7.51";
amountDetails.tax = "0.03";
amountDetails.shipping = "0.03";
PayPal.Api.Payments.Amount amount = new PayPal.Api.Payments.Amount();
amount.total = "7.56";
amount.currency = "USD";
amount.details = amountDetails;
PayPal.Api.Payments.Transaction transaction = new PayPal.Api.Payments.Transaction();
transaction.amount = amount;
transaction.description = "This is the payment transaction description.";
List<PayPal.Api.Payments.Transaction> transactions = new List<PayPal.Api.Payments.Transaction>();
transactions.Add(transaction);
PayPal.Api.Payments.FundingInstrument fundingInstrument = new PayPal.Api.Payments.FundingInstrument();
fundingInstrument.credit_card = creditCard;
List<PayPal.Api.Payments.FundingInstrument> fundingInstruments = new List<PayPal.Api.Payments.FundingInstrument>();
fundingInstruments.Add(fundingInstrument);
PayPal.Api.Payments.Payer payer = new PayPal.Api.Payments.Payer();
payer.funding_instruments = fundingInstruments;
payer.payment_method = "credit_card";
PayPal.Api.Payments.Payment payment = new PayPal.Api.Payments.Payment();
payment.intent = "sale";
payment.payer = payer;
payment.transactions = transactions;
PayPal.Api.Payments.Payment createdPayment = payment.Create(accessToken);
return Json(new JsonWrapper { Data = createdPayment });
}
When stepping through, the error occors on the line
PayPal.Api.Payments.Payment createdPayment = payment.Create(accessToken);
the exact error (as a Json Object):
"ClassName":"PayPal.Exception.PayPalException","Message":"Exception in HttpConnection Execute: Invalid HTTP response The remote server returned an error: (503) Server Unavailable.","Data":null,"InnerException":{"ClassName":"PayPal.Exception.ConnectionException","Message":"Invalid HTTP response The remote server returned an error: (503) Server Unavailable.","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":" at PayPal.HttpConnection.Execute(String payLoad, HttpWebRequest httpRequest)","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nExecute\nPayPalCoreSDK, Version=1.4.1.0, Culture=neutral, PublicKeyToken=null\nPayPal.HttpConnection\nSystem.String Execute(System.String, System.Net.HttpWebRequest)","HResult":-2146233088,"Source":"PayPalCoreSDK","WatsonBuckets":null},"HelpURL":null,"StackTraceString":" at PayPal.PayPalResource.ConfigureAndExecute[T](Dictionary`2 config, IAPICallPreHandler apiCallPreHandler, HttpMethod httpMethod, String resourcePath)\r\n at PayPal.PayPalResource.ConfigureAndExecute[T](APIContext apiContext, HttpMethod httpMethod, String resource, String payload)\r\n at PayPal.Api.Payments.Payment.Create(APIContext apiContext)\r\n at PayPal.Api.Payments.Payment.Create(String accessToken)\r\n at Scout.Controllers.PaymentController.RequestPermissions() in e:\\Scout\\Scout\\Controllers\\PaymentController.cs:line 1105","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nConfigureAndExecute\nPayPalCoreSDK, Version=1.4.1.0, Culture=neutral, PublicKeyToken=null\nPayPal.PayPalResource\nT ConfigureAndExecute[T](System.Collections.Generic.Dictionary`2[System.String,System.String], PayPal.IAPICallPreHandler, PayPal.HttpMethod, System.String)","HResult":-2146233088,"Source":"PayPalCoreSDK","WatsonBuckets":null
web.config (api keys are truncated here):
...
<configuration>
<configSections>
<section name="paypal" type="PayPal.Manager.SDKConfigHandler, PayPalCoreSDK" />
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
...
</configSections>
...
<paypal>
<settings>
<add name="endpoint" value="https://api.sandbox.paypal.com"/>
<add name="ClientID" value="AbayoRB3Eq6YxM6"/>
<add name="ClientSecret" value="EDWNfxDxnGZ3hWZW"/>
<add name="connectionTimeout" value="360000"/>
<!-- The number of times a request must be retried if the API endpoint is unresponsive -->
<add name="requestRetries" value="3"/>
</settings>
</paypal>
...
<log4net>
<appender name="FileAppender" type="log4net.Appender.FileAppender">
<file value="ScoutPaypalLog.log" />
<appendToFile value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger [%property{NDC}] %message%newline" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="FileAppender" />
</root>
</log4net>
As you can see, I have configured log4net, and it is recording data generated by another .dll I'm using (for RavenDB), but there are no entries made by PayPal.
Thanks!
I finally uninstalled the two nuget packages RestApiSDK and PayPalCoreSDK. I then restarted Visual Studio. Finally, I re-installed those same two packages.
Without changing any code, it started working.
I am attempting to implement authentication for a REST service implemented in WCF and hosted on Azure. I am using HttpModule to handle the AuthenticationRequest, PostAuthenticationRequest and EndRequest events. If the Authorization header is missing or if the token contained therein is invalid, during EndRequest I am setting the StatusCode on the Response to 401. However, I have determined that EndRequest is called twice, and on the second call the response has already had headers set, causing the code which sets the StatusCode to throw an exception.
I added locks to Init() to ensure that the handler wasn't being registered twice; still ran twice. Init() also ran twice, indicating that two instances of the HttpModule were being created. However, using Set Object ID in the VS debugger seems to indicate that the requests are actually different requests. I've verified in Fiddler that there is only one request being issued to my service from the browser.
If I switch to using global.asax routing instead of depending on the WCF service host configuration, the handler is only called once and everything works fine.
If I add configuration to the system.web configuration section as well as the system.webServer configuration section in Web.config, the handler is only called once and everything works fine.
So I have mitigations, but I really dislike behavior I don't understand. Why does the handler get called twice?
Here is a minimal repro of the problem:
Web.config:
<system.web>
<compilation debug="true" targetFramework="4.0" />
<!--<httpModules>
<add name="AuthModule" type="TestWCFRole.AuthModule, TestWCFRole"/>
</httpModules>-->
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="WebBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true" />
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" aspNetCompatibilityEnabled="true" />
<services>
<service name="TestWCFRole.Service1">
<endpoint binding="webHttpBinding" name="RestEndpoint" contract="TestWCFRole.IService1" bindingConfiguration="HttpSecurityBinding" behaviorConfiguration="WebBehavior"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost/" />
</baseAddresses>
</host>
</service>
</services>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
</webHttpEndpoint>
</standardEndpoints>
<bindings>
<webHttpBinding>
<binding name="HttpSecurityBinding" >
<security mode="None" />
</binding>
</webHttpBinding>
</bindings>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="AuthModule" type="TestWCFRole.AuthModule, TestWCFRole"/>
</modules>
<directoryBrowse enabled="true"/>
</system.webServer>
Http module:
using System;
using System.Web;
namespace TestWCFRole
{
public class AuthModule : IHttpModule
{
/// <summary>
/// You will need to configure this module in the web.config file of your
/// web and register it with IIS before being able to use it. For more information
/// see the following link: http://go.microsoft.com/?linkid=8101007
/// </summary>
#region IHttpModule Members
public void Dispose()
{
//clean-up code here.
}
public void Init(HttpApplication context)
{
// Below is an example of how you can handle LogRequest event and provide
// custom logging implementation for it
context.EndRequest += new EventHandler(OnEndRequest);
}
#endregion
public void OnEndRequest(Object source, EventArgs e)
{
HttpContext.Current.Response.StatusCode = 401;
}
}
}
When an ASP.net application starts up, to maximize performance the ASP.NET Worker process will instantiate as many HttpApplication objects as it needs. Each HttpApplication object, will also instantiate one copy of each IHttpModule that is registered and call the Init method! That's really an internal design of the ASP.NET process running under IIS (or cassini which is VS built in webserver). Might be because your ASPX page has links to other resources which your browser will try to download, an external resource, and iframe, a css file, or maybe ASP.NET Worker Process behavior.
Luckily it's not the case for Global.asax:
Here's from MSDN:
The Application_Start and Application_End methods are special methods
that do not represent HttpApplication events. ASP.NET calls them once
for the lifetime of the application domain, not for each
HttpApplication instance.
However HTTPModule's init method is called once for every instance of the HttpApplication class after all modules have been created
The first time an ASP.NET page or process is requested in an
application, a new instance of HttpApplication is created. However, to
maximize performance, HttpApplication instances might be reused for
multiple requests.
And illustrated by the following diagram:
If you want code that's guaranteed to run just once, you can either use Application_Start of the Global.asax or set a flag and lock it in the underlying module which is don't think is a good practice for the sake of Authentication!
Sorry no clue to why it could be called twice, however EndRequest can end up being called for multiple reasons. request finished, request was aborted, some error happened. So i wouldn't put my trust in assuming that if you get there, you actually have a 401, it could be for other reasons.
I'd just keep my logic in the AuthenticateRequest pipeline:
public class AuthenticationModule : IHttpModule
{
public void Dispose() { }
public void Init(HttpApplication context)
{
context.AuthenticateRequest += Authenticate;
}
public static void Authenticate(object sender, EventArgs e)
{
// authentication logic here
//.............
if (authenticated) {
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(myUser, myRoles);
}
// failure logic here
//.............
}
}
I have taken over a domain that had was running an old version of Community Server. Needless to say the bots are spamming me trying to find holes.
I'd like to block entire IP blocks before System.Web.HttpRequest.ValidateInputIfRequiredByConfig() is fired. I have a IHttpModule that I have tried but I assume it's getting called after because HealthMonitoring is catching the Exceptions. Here is the module:
public class IpBlockerModule : IHttpModule
{
private static readonly string[] Hacks = new[]
{
"60.169.73.",
"60.169.75.",
"61.160.232.",
"61.160.207.",
"92.85.161."
};
public void Dispose()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += (Application_BeginRequest);
}
private void Application_BeginRequest(object source, EventArgs e)
{
var context = ((HttpApplication) source).Context;
var ipAddress = context.Request.UserHostAddress;
if (!IsHackIpAddress(ipAddress))
{
context.Response.StatusCode = 403; // (Forbidden)
}
}
private static bool IsHackIpAddress(string ip)
{
if (ip == null) return true;
return Hacks.Any(x => x.StartsWith(ip));
}
}
And the relevent web.config sections:
<system.web>
<httpModules>
<add name="IpBlockerModule" type="MyNameSpace.IpBlockerModule" />
</httpModules>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true" >
<add name="IpBlockerModule" type="MyNameSpace.IpBlockerModule" preCondition="" />
</modules>
</system.webServer>
The reasoning behind this is my inbox is getting spammed from all the
A potentially dangerous Request.Path value was detected from the
client
and
A potentially dangerous Request.Form value was detected from the client
notifications. Is something wrong with my Module, or am I correct in assuming modules don't get fired until after the fact?
As an alternative solution have you considered letting IIS do the work for you? This way the request never makes it to your application. You can do this via the web.config and there's an article detailing the process located here. The following example is copied directly from that article and would be placed inside the <system.webServer> section of your web.config:
<security>
<ipSecurity allowUnlisted="true"> <!-- this line allows everybody, except those listed below -->
<clear/> <!-- removes all upstream restrictions -->
<add ipAddress="83.116.19.53"/> <!-- blocks the specific IP of 83.116.19.53 -->
<add ipAddress="83.116.119.0" subnetMask="255.255.255.0"/> <!--blocks network 83.116.119.0 to 83.116.119.255-->
<add ipAddress="83.116.0.0" subnetMask="255.255.0.0"/> <!--blocks network 83.116.0.0 to 83.116.255.255-->
<add ipAddress="83.0.0.0" subnetMask="255.0.0.0"/> <!--blocks entire /8 network of 83.0.0.0 to 83.255.255.255-->
</ipSecurity>
</security>
You can also add the ability to get and log IP addresses so as to identify and block only the spammy ones.
Here's C# code to get IP addresses
string ipadd;
ipadd = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (ipadd == "" || ipaddress == null)
ipadd = Request.ServerVariables["REMOTE_ADDR"];
I noticed that the link in the answer above is dead, so use this well-detailed article here