How to integrate paytm gateway in asp.net web application - asp.net

I am trying to integrate Paytm in an ASP.NET website. Payment processing is going well, but when a transaction is completed, it redirects to my "callbackurl" page.
Here I don`t know how to read the response of the transaction. I checked my callback page using inspect element but there was no json or any error message or message in console.

You can call this function during your page load event of callback url. If checksumhash is matched then you can call additional parameters.
String merchantKey = "****************"; // Replace the with the Merchant Key provided by Paytm at the time of registration.
Dictionary<string, string> parameters = new Dictionary<string, string>();
string paytmChecksum = "";
foreach (string key in Request.Form.Keys)
{
parameters.Add(key.Trim(), Request.Form[key].Trim());
}
if (parameters.ContainsKey("CHECKSUMHASH"))
{
paytmChecksum = parameters["CHECKSUMHASH"];
parameters.Remove("CHECKSUMHASH");
}
if (CheckSum.verifyCheckSum(merchantKey, parameters, paytmChecksum))
{
lbl_status.Text = parameters["STATUS"];
Response.Write("Checksum Matched");
}
else
{
Response.Write("Checksum MisMatch");
}

Related

Application Insights - How to set Custom Operation Id

In our current on-prem setup we have 20+ .net core 3.1 API apps (separate ASP.NET Core API Apps). We have started migrating 2 APi app to Azure App Service tagged with a single Application Insights instance.
In On-Prem, we use some other log framework which the rest of the 18 Apps. All these API apps talk to each other and all the logs are tied to some unique_id in on-prem.
Now, for the apis which is in Azure, we need to leverage the same unique_Id and co-relate everything.
In order to achieve it, I started exploring the functionality of setting a same Operation Id for the 2 apps which are hosted in azure.
Created TelemetrInitializer in both the APIs. and if i set Operational Id as shown below in both the APIs, it's works. All the logs are tied to Single Operation Id "12345"
telemetry.Context.Operation.Id = "12345";
However, as it is obvious to make the Operation Id to be dynamic, I have changed it to the below in my First API
telemetry.Context.Operation.Id = "CR" + Guid.NewGuid().ToString();
So, the next challenge is, I need to tie this new Operation Id in my second API's TelemetryInitiializer. In order to achieve that I tried to grab the Request-Id Header in the TelemetryInitializer of 2nd API. It's always NULL.
Is there a way to achieve this?
Thanks,
Praveen Sreeram.
tldr: This is possible by disabling the built in dependency tracking in .NET Core and App Insights and handling it on your own. In most cases, the best thing to do is let .NET Core and App Insights do the tracking.
I uploaded a simple WebAPI app with the code I'm going to go over to Github: https://github.com/SamaraSoucy-MSFT/customoperationid
There are two things that need to be overridden to get both the headers and App Insights to get the custom operation Id. The first is the Activity the wraps the HttpClient as that controls the correlation headers. The second is the dependency tracing in App Insights.
It is possible to disable Actions completely in your HttpClients, but to minimize side effects, you can just remove the one in the client by setting Activity.Current = null
var operationId = "CR" + Guid.NewGuid().ToString();
var url = "https://www.microsoft.com";
using (var client = new HttpClient())
{
using (var requestMessage =
new HttpRequestMessage(HttpMethod.Get, url))
{
//Makes the headers configurable
Activity.Current = null;
//set correlation header manually
requestMessage.Headers.Add("Request-Id", operationId);
await client.SendAsync(requestMessage);
}
}
The next step is to remove the App Insights default tracking for this request. Again, you can disable dependency tracking completely, or you can filter out the default telemetry for this request. Processors are registered inside the Startup class just like initializers.
services.AddApplicationInsightsTelemetryProcessor<CustomFilter>();
public class CustomFilter : ITelemetryProcessor
{
private ITelemetryProcessor Next { get; set; }
// next will point to the next TelemetryProcessor in the chain.
public CustomFilter(ITelemetryProcessor next)
{
this.Next = next;
}
public void Process(ITelemetry item)
{
// To filter out an item, return without calling the next processor.
if (!OKtoSend(item)) { return; }
this.Next.Process(item);
}
// Example: replace with your own criteria.
private bool OKtoSend(ITelemetry item)
{
var dependency = item as DependencyTelemetry;
if (dependency == null) return true;
if (dependency.Type == "Http"
&& dependency.Data.Contains("microsoft.com")
//This key is just there to help identify the custom tracking
&& !dependency.Context.GlobalProperties.ContainsKey("keep"))
{
return false;
}
return true;
}
}
Finally, in the method that makes the remote call, you need to inject a telemetry client and call TelemetryClient.TrackDependency()
var operationId = "CR" + Guid.NewGuid().ToString();
//setup telemetry client
telemetry.Context.Operation.Id = operationId;
if (!telemetry.Context.GlobalProperties.ContainsKey("keep"))
{
telemetry.Context.GlobalProperties.Add("keep", "true");
}
var startTime = DateTime.UtcNow;
var timer = System.Diagnostics.Stopwatch.StartNew();
//continue setting up context if needed
var url = "https:microsoft.com";
using (var client = new HttpClient())
{
//Makes the headers configurable
Activity.Current = null;
using (var requestMessage =
new HttpRequestMessage(HttpMethod.Get, url))
{
//Makes the headers configurable
Activity.Current = null;
//set header manually
requestMessage.Headers.Add("Request-Id", operationId);
await client.SendAsync(requestMessage);
}
}
//send custom telemetry
telemetry.TrackDependency("Http", url, "myCall", startTime, timer.Elapsed, true);

How to send List of objects to google execution api and handle it in google apps script

In general I want to export data from asp.net mvc application to Google Sheets for example list of people. I've already set up connection and authenticated app with my Google account (trough OAuth2) but now I'm trying to send my list of objects to api and then handle it in script (by putting all data in new file) and couldn't get my head around this.
Here is some sample code in my app that sends the request.
public async Task<ActionResult> SendTestData()
{
var result = new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).
AuthorizeAsync(CancellationToken.None).Result;
if (result.Credential != null)
{
string scriptId = "MY_SCRIPT_ID";
var service = new ScriptService(new BaseClientService.Initializer
{
HttpClientInitializer = result.Credential,
ApplicationName = "Test"
});
IList<object> parameters = new List<object>();
var people= new List<Person>(); // next i'm selecting data from db.Person to this variable
parameters.Add(people);
ExecutionRequest req = new ExecutionRequest();
req.Function = "testFunction";
req.Parameters = parameters;
ScriptsResource.RunRequest runReq = service.Scripts.Run(req, scriptId);
try
{
Operation op = runReq.Execute();
if (op.Error != null)
{
// The API executed, but the script returned an error.
// Extract the first (and only) set of error details
// as a IDictionary. The values of this dictionary are
// the script's 'errorMessage' and 'errorType', and an
// array of stack trace elements. Casting the array as
// a JSON JArray allows the trace elements to be accessed
// directly.
IDictionary<string, object> error = op.Error.Details[0];
if (error["scriptStackTraceElements"] != null)
{
// There may not be a stacktrace if the script didn't
// start executing.
Newtonsoft.Json.Linq.JArray st =
(Newtonsoft.Json.Linq.JArray)error["scriptStackTraceElements"];
}
}
else
{
// The result provided by the API needs to be cast into
// the correct type, based upon what types the Apps
// Script function returns. Here, the function returns
// an Apps Script Object with String keys and values.
// It is most convenient to cast the return value as a JSON
// JObject (folderSet).
Newtonsoft.Json.Linq.JObject folderSet =
(Newtonsoft.Json.Linq.JObject)op.Response["result"];
}
}
catch (Google.GoogleApiException e)
{
// The API encountered a problem before the script
// started executing.
AddAlert(Severity.error, e.Message);
}
return RedirectToAction("Index", "Controller");
}
else
{
return new RedirectResult(result.RedirectUri);
}
}
The next is how to handle this data in scripts - are they serialized to JSON there?
The execution API calls are essentially REST calls so the payload should be serialized as per that. Stringified JSON is typically fine. Your GAS function should then parse that payload to consume the encoded lists
var data = JSON.parse(payload);

SignalR recording when a Web Page has closed

I am using MassTransit request and response with SignalR. The web site makes a request to a windows service that creates a file. When the file has been created the windows service will send a response message back to the web site. The web site will open the file and make it available for the users to see. I want to handle the scenario where the user closes the web page before the file is created. In that case I want the created file to be emailed to them.
Regardless of whether the user has closed the web page or not, the message handler for the response message will be run. What I want to be able to do is have some way of knowing within the response message handler that the web page has been closed. This is what I have done already. It doesnt work but it does illustrate my thinking. On the web page I have
$(window).unload(function () {
if (event.clientY < 0) {
// $.connection.hub.stop();
$.connection.exportcreate.setIsDisconnected();
}
});
exportcreate is my Hub name. In setIsDisconnected would I set a property on Caller? Lets say I successfully set a property to indicate that the web page has been closed. How do I find out that value in the response message handler. This is what it does now
protected void BasicResponseHandler(BasicResponse message)
{
string groupName = CorrelationIdGroupName(message.CorrelationId);
GetClients()[groupName].display(message.ExportGuid);
}
private static dynamic GetClients()
{
return AspNetHost.DependencyResolver.Resolve<IConnectionManager>().GetClients<ExportCreateHub>();
}
I am using the message correlation id as a group. Now for me the ExportGuid on the message is very important. That is used to identify the file. So if I am going to email the created file I have to do it within the response handler because I need the ExportGuid value. If I did store a value on Caller in my hub for the web page close, how would I access it in the response handler.
Just in case you need to know. display is defined on the web page as
exportCreate.display = function (guid) {
setTimeout(function () {
top.location.href = 'GetExport.ashx?guid=' + guid;
}, 500);
};
GetExport.ashx opens the file and returns it as a response.
Thank you,
Regards Ben
I think a better bet would be to implement proper connection handling. Specifically, have your hub implementing IDisconnect and IConnected. You would then have a mapping of connectionId to document Guid.
public Task Connect()
{
connectionManager.MapConnectionToUser(Context.ConnectionId, Context.User.Name);
}
public Task Disconnect()
{
var connectionId = Context.ConnectionId;
var docId = connectionManager.LookupDocumentId(connectionId);
if (docId != Guid.Empty)
{
var userName = connectionManager.GetUserFromConnectionId(connectionId);
var user = userRepository.GetUserByUserName(userName);
bus.Publish( new EmailDocumentToUserCommand(docId, user.Email));
}
}
// Call from client
public void GenerateDocument(ClientParameters docParameters)
{
var docId = Guid.NewGuid();
connectionManager.MapDocumentIdToConnection(Context.ConnectionId, docId);
var command = new CreateDocumentCommand(docParameters);
command.Correlationid = docId;
bus.Publish(command);
Caller.creatingDocument(docId);
}
// Acknowledge you got the doc.
// Call this from the display method on the client.
// If this is not called, the disconnect method will handle sending
// by email.
public void Ack(Guid docId)
{
connectionManager.UnmapDocumentFromConnectionId(connectionId, docId);
Caller.sendMessage("ok");
}
Of course this is from the top of my head.

WCF Adding Custom Headers and Session

I have a web page that uses a WCF service. Multiple users maybe using the web page at any one time and therefore making requests to the WCF service which is on a remote machine.
Each user on the web page gets a unique ID, I want to add this unique ID to the request header of each request made by that user.
So far I have created the following code which correctly adds a header to the WCF message.
public class HeaderIdPusher : IClientMessageInspector
{
private static readonly string _balancerKey = "balancerId";
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
Guid userId = Guid.NewGuid();
HttpRequestMessageProperty httpRequestMessage;
object httpRequestMessageObject;
if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name, out httpRequestMessageObject))
{
httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty;
if (string.IsNullOrEmpty(httpRequestMessage.Headers[_balancerKey]))
{
httpRequestMessage.Headers[_balancerKey] = userId.ToString();
}
}
else
{
httpRequestMessage = new HttpRequestMessageProperty();
httpRequestMessage.Headers.Add(_balancerKey, userId.ToString());
request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage);
}
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
}
However I am no stuck because I can't get the ID to persist between requests. You can see here that at the moment I am generating an ID for each request, however I can't store this in the Session of the page the user is on because the HttpContext.Current is null. Is there another way of storing this? Is there another way of passing in the HttpContext of the user on my web page?
The problem is discussed here:
http://social.msdn.microsoft.com/forums/en-US/wcf/thread/27896125-b61e-42bd-a1b0-e6da5c23e6fc
Essentially WCF doesn't have sessions, as you could pass anything you wanted as a parameter (in this case, your Unique ID) and handle it any way you wanted in your implementation.
After much hacking I found a solution, it isn't great but it works.
In the ASP.NET page before I create the WCF service instance I create an address header and endpoint:
AddressHeader header = AddressHeader.CreateAddressHeader("MyKey", "http://www.w3.org/2005/08/addressing", "MyValue");
EndpointAddress endpoint = new EndpointAddress(new Uri("http://www.myservice.com/service"), header);
Then I create an instance of the service passing in the endpoint:
using (WcfService service = new WcfService(_configName,endpoint ))
{
}
This gets the data into the WCF service, then in the HeaderIdPusher : IClientMessageInspector detailed above I pull the header value out:
public class HeaderIdPusher : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
string id = "Not found";
if(channel.RemoteAddress.Headers.Any(x=>x.Name == "MyKey"))
{
id = channel.RemoteAddress.Headers.First(x => x.Name == "MyKey").GetValue<string>();
}
This solution isn't ideal and it puts extra data into the SOAP message but it is the only way I have found of sharing data from the ASP.NET page with the WCF process.

Problem with null object reference in Url.Action in MVC3 project

I am trying to set up a mocking scenario for my payment processor on a web site. Normally, my site redirects to the processor site, where the user pays. The processor then redirects back to my site, and I wait for an immediate payment notification (IPN) from the processor. The processor then posts to my NotifyUrl, which routes to the Notify action on my payments controller (PayFastController). To mock, I redirect to a local action, which after a conformation click, spawns a thread to post the IPN, as if posted by the processor, and redirects back to my registration process.
My mock processor controller uses the following two methods to simulate the processor's response:
[HttpGet]
public RedirectResult Pay(string returnUrl, string notifyUrl, int paymentId)
{
var waitThread = new Thread(Notify);
waitThread.Start(new { paymentId, ipnDelay = 1000 });
return new RedirectResult(returnUrl);
}
public void Notify(dynamic data)
{
// Simulate a delay before PayFast
Thread.Sleep(1000);
// Delegate URL determination to the model, vs. directly to the config.
var notifyUrl = new PayFastPaymentModel().NotifyUrl;
if (_payFastConfig.UseMock)
{
// Need an absoluate URL here just for the WebClient.
notifyUrl = Url.Action("Notify", "PayFast", new {data.paymentId}, "http");
}
// Use a canned IPN message.
Dictionary<string, string> dict = _payFastIntegration.GetMockIpn(data.paymentId);
var values = dict.ToNameValueCollection();
using (var wc = new WebClient())
{
// Just a reminder we are posting to Trocrates here, from PayFast.
wc.UploadValues(notifyUrl, "POST", values);
}
}
However, I get an 'Object reference not set to an instance of an object.' exception on the following line:
notifyUrl = Url.Action("Notify", "PayFast", new {data.paymentId}, "http");
data.paymentId has a valid value, e.g. 112, so I'm not passing any null references to the Url.Action method. I suspect I have lost some sort of context somewhere by calling Notify on a new thread. However, if I use just notifyUrl = Url.Action("Notify", "PayFast");, I avoid the exception, but I get a relative action URL, where I need the overload that takes a protocol parameter, as only that overload gives me the absolute URL that WebClient.UploadValues says it needs.
When you are inside the thread you no longer have access to the HttpContext and the Request property which the Url helper relies upon. So you should never use anything that relies on HttpContext inside threads.
You should pass all the information that's needed to the thread when calling it, like this:
waitThread.Start(new {
paymentId,
ipnDelay = 1000,
notifyUrl = Url.Action("Notify", "PayFast", new { paymentId }, "http")
});
and then inside the thread callback:
var notifyUrl = new PayFastPaymentModel().NotifyUrl;
if (_payFastConfig.UseMock)
{
// Need an absoluate URL here just for the WebClient.
notifyUrl = data.notifyUrl;
}

Resources