Insert Guid with NLOG - guid

I am getting the error
Exception occurred in NLog ---> System.Data.SqlClient.SqlException: Conversion failed when converting from a character string to uniqueidentifier.
when I try to insert a NULL in the UserId column of the table which can take NULLS.
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
throwExceptions="true" internalLogFile="C:\Development\Projects\Pearson\ARIES\Development\Websites\ARIES.Web\NLog.log" internalLogLevel="Debug" >
<!-- make sure to set 'Copy To Output Directory' option for this file -->
<!-- go to http://nlog-project.org/wiki/Configuration_file for more information -->
<targets>
<target xsi:type="AsyncWrapper" queueLimit="2000" overflowAction="Grow" name="AsyncWrapperLogger" batchSize="1000">
<target xsi:type="Database"
name="Database"
connectionStringName="ApplicationServices">
<commandText>
insert into Logs(UserId, Level, Message, Exception, StackTrace, DateCreated) values(CASE WHEN #UserId IS NOT NULL AND #UserId = CAST('00000000-0000-0000-0000-000000000000' AS uniqueidentifier) THEN #UserId ELSE #UserId END, #Level, #Message, #Exception, #StackTrace, #DateCreated);
</commandText>
<parameter name="#UserId" layout="${event-context:item=${guid:format=UserId}}"/>
<parameter name="#Level" layout="${level}"/>
<parameter name="#Message" layout="${message}"/>
<parameter name="#Exception" layout="${exception}"/>
<parameter name="#StackTrace" layout="${stacktrace}"/>
<parameter name="#DateCreated" layout="${date}"/>
</target>
</target>
</targets>
<rules>
<logger name="*" writeTo="Database"/>
</rules>
</nlog>
public static void Write(string message, Exception ex)
{
var logEventInfo = new LogEventInfo(NLog.LogLevel.Error, "", message);
if (HttpContext.Current != null)
{
logEventInfo.Properties.Add("UserId", Guid.NewGuid());
}
logEventInfo.Exception = ex;
logger.Log(logEventInfo);
}

Fixed it by using SQL Profiler. It was sending an empty string for the null GUID.
insert into Logs(UserId, Level, Message, Exception, StackTrace, DateCreated) values(CASE WHEN #UserId = '' THEN NULL ELSE convert(uniqueidentifier, #UserId) END, #Level, #Message, #Exception, #StackTrace, #DateCreated);

Related

Wait for asynchronous logging to finish before Thread ends slf4j/log4j2

I'm using an asynchronous database logging setup with slf4j/log4j2. All is working as expected.
The only drawback is, that sometimes when the server is shut down the logger has not completed writing to the database (e.g. if there was a burst before shutdown).
I get:
WARN AsyncLoggerConfigDisruptor: shutdown timed out after 0
MILLISECONDS Log4j2-TF-1-AsyncLoggerConfig-1 ERROR Attempted to append
to non-started appender databaseAppender
And I lose everything that was in the logger-buffer.
Is there a way in slf4j or log4j2 to wait for the asynchronous logger to finish (e.g. a blocking call at the end of a task)?
Or at least to get the size of the buffer, that still needs to be written?
Currently, I use a setup with synchronous file logger and an asynchronous database logger, so the data is still in the file...
--> Edit 02/28/19
Here is a quick and dirty example code:
protected static final Logger logger = LoggerFactory.getLogger(App.class);
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable task = new TestLogging(i);
executor.submit(task);
}
executor.shutdown();
System.out.println("Done");
//LogManager.shutdown();
}
private static class TestLogging implements Runnable {
private int i;
public TestLogging(int i) {
this.i=i;
}
public void run() {
// Generate a big string for DB test
StringBuffer b=new StringBuffer();
IntStream.range(0, 1000).parallel().forEach(i -> b.append(UUID.randomUUID().toString()));
// Writing to context for logging
MDC.put("test", "test"+i);
MDC.put("test1", b.toString());
// Log 1000 lines
IntStream.range(0, 1000).forEach(j -> logger.error("Exception " + j + "-"+ i, new RuntimeException()));
}
}
The configuration xml:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<File name="MyFile" fileName="all.log" immediateFlush="false"
append="false">
<PatternLayout
pattern="%d{yyy-MM-dd HH:mm:ss.SSS} tx.id=%X{test} tx.content=%X{test1} [%t] %-5level %logger{36} - %msg%n" />
</File>
<JDBC name="databaseAppender" tableName="log_test">
<PoolingDriver connectionString="jdbc:oracle:thin:#centos.fritz.box:1521:orcl" userName="test" password="test" driverClassName="oracle.jdbc.driver.OracleDriver"/>
<Column name="LOG_ID" pattern="%u" />
<Column name="ENTRY_DATE" isEventTimestamp="true" />
<Column name="LOGGER" pattern="%logger" />
<Column name="LOG_LEVEL" pattern="%level" />
<Column name="MESSAGE" pattern="%m" />
<Column name="EXCEPTION" pattern="%throwable" />
<Column name="ID" pattern="%X{test}" />
<Column name="XML" pattern="%X{test1}" />
</JDBC>
</Appenders>
<Loggers>
<AsyncRoot level="info">
<AppenderRef ref="databaseAppender" />
</AsyncRoot>
<Logger name="com.test" level="trace" includeLocation="true">
<AppenderRef ref="MyFile" />
</Logger>
</Loggers>
</Configuration>
And for Oracle the DDL:
CREATE TABLE "TEST"."LOG_TEST"
( "LOG_ID" VARCHAR2(100 BYTE),
"ENTRY_DATE" TIMESTAMP (6),
"LOGGER" VARCHAR2(100 BYTE),
"LOG_LEVEL" VARCHAR2(100 BYTE),
"MESSAGE" CLOB,
"EXCEPTION" CLOB,
"ID" VARCHAR2(20 BYTE),
"XML" CLOB,
PRIMARY KEY ("LOG_ID"))
If I use the
LogManager.shutdown();
The logging doesn't even start. Without, depending on the DB, I get about 500-1000 lines in the DB, before the error appears.
The logging in the real database will be much more sparse, this is just a worst-case test... and as mentioned, the logging in the file works. It would just be nice, to have a consistent logging in DB and file, even if the service is shut down.

'Endpoint not found.' while consuming rest service of WCF through browser

I have created WCF Rest service that take input/para from client and save it in database and knowledge with identity of table in which data is added.When I am consuming service throgh client that is nothing but web application making url as web request and getting proper output.But when I am consuming through browser getting error.
First I tried like this :-
http://localhost:Portnumber/Test.svc/ADD/Bodywash/Orange/50
after that like this
ht
tp://localhost:Portnumber/Test.svc/ADD?Name=Bodywash&CategoryName=Orange&Price=50
I am getting error'Entpoint not found'.How to consume rest service through browser?Will I able to do that
// Code of service
-- Table
CREATE TABLE [dbo].[Product](
[ProductId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NULL,
[CategoryName] [varchar](50) NULL,
[Price] [int] NULL
)
-- Sp
ALTER procedure [dbo].[proc_InsertProduct]
(
#id int out,
#Name nvarchar(50),
#CategoryName nvarchar(50),
#Price int
)
as insert into Product
(
Name,
CategoryName,
Price
)
values
(
#Name,
#CategoryName,
#Price
)
set #id = ##identity
return #id
-- Interface
public interface ITest
{
[WebInvoke(UriTemplate = "ADD/{Name}/{CategoryName}/{Price}", Method = "POST", ResponseFormat = WebMessageFormat.Json)]
int InsertProduct(string Name, string CategoryName, string Price);
}
-- class
public class Test : ITest
{
public int InsertProduct(string Name, string CategoryName, string Price)
{
string constr = ConfigurationManager.ConnectionStrings["SampleConnectionString"].ConnectionString;
SqlConnection con = new SqlConnection(constr);
SqlCommand cmd = new SqlCommand("proc_InsertProduct", con);
cmd.CommandType = CommandType.StoredProcedure;
con.Open();
cmd.Parameters.AddWithValue("#Name", Name);
cmd.Parameters.AddWithValue("#CategoryName", CategoryName);
cmd.Parameters.AddWithValue("#Price", Price);
cmd.Parameters.Add("#id", SqlDbType.Int);
cmd.Parameters["#id"].Direction = ParameterDirection.Output;//Output parameter
cmd.ExecuteNonQuery();
con.Close();
int result = (int)(cmd.Parameters["#id"].Value);
return result;//returning id
}
}
// WebConfig
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<connectionStrings>
<add name="SampleConnectionString" connectionString="Data Source=xxx.xxx.x.x;Initial Catalog=sample;Persist Security Info=True;User ID=sa;Password=xxxx" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<services>
<service name="RestApiTest.Test" behaviorConfiguration="serviceBehavior">
<endpoint address="" binding="webHttpBinding" contract="RestApiTest.ITest" behaviorConfiguration="web">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="serviceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
Continuation from comments - updating as answer due to size limit of comments
This would work though I wont recommend doing it - respecting the HTTP Verbs, all get request should be GET, add should be POST, update should be PUT (PATCH in case for patches) and delete should be DELETE methods. I would suggest you to revert this method back to POST.
Because client might be accessing it through browser - By this, I'm assuming that you mean to say that this service will be consumed from client side using JavaScript code. If that is true, then you dont have to worry about it. if someone POSTs data (for eg, using $.ajax or $.post in case of jQuery) to your REST service, you will get data properly.
To make this method a standard POST method, please change the method signature to accept a comples object instead of getting Name, CategoryName & Price from the route. Change this int InsertProduct(string Name, string CategoryName, string Price); to something like int InsertProduct(Product product); where 'Product' class has required properties. You can find a sample implementation here - POST complex object to WCF REST.

PayPal RestApiSDK .NET http 503 Server Unavailable

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.

AJAX Enabled WCF Service fails if Date Property is DateTime.MinValue

If a AJAX-Enabled WCF should return an Object with a Date Property which is Nothing a Request to this Service fails.
Test.svc
Imports System.ServiceModel
Imports System.ServiceModel.Activation
Imports System.ServiceModel.Web
Imports System.Runtime.Serialization
<ServiceContract(Namespace:="WebApp")>
<AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)>
Public Class Test
<OperationContract()>
<WebGet()>
Public Function TestOperation() As CompositeType
Dim obj As New CompositeType
obj.DateProp = Nothing
obj.StringProp = "Test"
Return obj
End Function
End Class
<DataContract()>
Public Class CompositeType
<DataMember()>
Public Property DateProp() As Date
<DataMember()>
Public Property StringProp() As String
End Class
scripttag on Testform.aspx
<script type="text/javascript">
$(document).ready(function () {
$.getJSON('./Test.svc/TestOperation', function (data) {
alert(data.d.DateProp);
});
});
</script>
Web.config (serviceModel section)
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="WebApp.TestAspNetAjaxBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="WebApp.Test">
<endpoint address="" behaviorConfiguration="WebApp.TestAspNetAjaxBehavior"
binding="webHttpBinding" contract="WebApp.Test" />
</service>
</services>
</system.serviceModel>
Chrome displays on this call the following error message: "failed to load resource".
Has anyone an explanation/idea for this behaviour and how are you supposed to prevent this problem?
Thanks for your advice ;)
If you want to be able to assign Nothing to a DateTime field you should make it nullable:
<DataMember()>
Public Property DateProp() As Nullable(Of DateTime)
I am not a VB.NET expert but as far as I know the Date keyword in VB.NET is an alias to the DateTime structure (which is not nullable), except that VB.NET must be doing some black voodoo magic to allow you to assign Nothing to it. Except that when the serializer attempts to serialize it into JSON the following exception is thrown:
There was an error while trying to serialize parameter
WebApp:TestOperationResult. The InnerException message was 'DateTime
values that are greater than DateTime.MaxValue or smaller than
DateTime.MinValue when converted to UTC cannot be serialized to
JSON.'. Please see InnerException for more details.

NLog - DDL for Log Table and Setting the ConnectionString Programmatically

1:
Is there a create statement for the Database Target Log Table for all the possible fields documented somewhere? I created one by guessing and I could check the source, but it would be handy if the generic SQL was available. I searched StackOverflow and the NLog site, but the SQL I found was dated and contained incorrect field types.
2:
If you're configuring a database target from a nlog.config file, how do you programmatically set the connection string? Something like:
Logger dbLogger = LogManager.GetLogger("dbLogger");
DatabaseTarget t = dbLogger.GetDatabaseTarget;
t.ConnectionString = "...";
in application_start.
Thanks in advance.
Is this below sample helpful to you? I found this in nlog site. Have you tried this?
<target xsi:type="Database" name="db">
<!-- SQL command to be executed for each entry -->
<commandText>INSERT INTO [LogEntries](TimeStamp, Message, Level, Logger) VALUES(getutcdate(), #msg, #level, #logger)</commandText>
<!-- parameters for the command -->
<parameter name="#msg" layout="${message}" />
<parameter name="#level" layout="${level}" />
<parameter name="#logger" layout="${logger}" />
<!-- connection string -->
<dbProvider>System.Data.SqlClient</dbProvider>
<connectionString>server=.\SQLEXPRESS;database=MyLogs;integrated security=sspi</connectionString>
<!-- commands to install database -->
<install-command>
<text>CREATE DATABASE MyLogs</text>
<connectionString>server=.\SQLEXPRESS;database=master;integrated security=sspi</connectionString>
<ignoreFailures>true</ignoreFailures>
</install-command>
<install-command>
<text>
CREATE TABLE LogEntries(
id int primary key not null identity(1,1),
TimeStamp datetime2,
Message nvarchar(max),
level nvarchar(10),
logger nvarchar(128))
</text>
</install-command>
<!-- commands to uninstall database -->
<uninstall-command>
<text>DROP DATABASE MyLogs</text>
<connectionString>server=.\SQLEXPRESS;database=master;integrated security=sspi</connectionString>
<ignoreFailures>true</ignoreFailures>
</uninstall-command>
</target>

Resources