Fetching JSON data with .netcore from a web api - .net-core

I made an api which have some data for example www.example.com/data/select?indent=on&q=title:asthma
gives the data in JSON format like
{
"responseHeader":{
"status":0,
"QTime":2,
"params":
{
"q":"title:asthma",
"indent":"on",
"wt":"json"
},
"response":{"numFound":1,"start":0, docs:[
{
"tstamp": "xxxx"
"id": "xxxxx"
"title": "Asthma is a medical term"
"url": "www.example.com/xxxx"
"content":"xxxxx"
}]}
}}
I want to call the same url from my .netcore application such that I can have title and url from the response and show it to my .netcore application.
As a new to .netcore it is pretty tricky to get used to MVC architecture. My model look like this
namespace searchEngineTesting.Models
{
public class SearchModel
{
public string Title {get; set;}
public string Source {get; set;}
}
}
How can I use controller that whenever triggers take a string as an input for example cancer and put it to the title of the api like www.example.com/data/select?indent=on&q=title:cancer and fetch the title and url from the response.

You could fetch json data like below:
[HttpGet]
public async Task<JsonResult> Get()
{
var model = new SearchModel();
var url = "https://localhost:5001/api/values/test";//it should be the url of your api
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.GetAsync(url))
{
using (var content = response.Content)
{
//get the json result from your api
var result = await content.ReadAsStringAsync();
var root = (JObject)JsonConvert.DeserializeObject(result);
var items = root.SelectToken("responseHeader").Children().OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach(var item in items)
{
if(item.Key== "response")
{
var key = item.Value.SelectToken("").OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach (var k in key)
{
if(k.Key== "docs")
{
var tests = JsonConvert.DeserializeObject<JArray>(k.Value.ToString());
var data = k.Value.SelectToken("").Children().First();
var test = data.SelectToken("").Children().OfType<JProperty>().ToDictionary(p => p.Name, p => p.Value);
foreach (var t in test)
{
if (t.Key == "url")
{
model.Source = t.Value.ToString();
}
else if (t.Key=="title")
{
model.Title = t.Value.ToString();
}
}
}
}
}
}
return new JsonResult(model);
}
}
}
}
[HttpGet("[Action]")]
public string test()
{
//for easy testing,I just read your json file and return string
var jsonstring = System.IO.File.ReadAllText("C:\\test.json");
return jsonstring;
}

Related

Razorpay payment gateway integration asp.net core

I am beginner to integrate razorpay payment gateway on our angular and asp.net core website. Getting 500 error while posting the data to gateway url. Please check my code and pour your answers. Ia m searching it for nearly 2 days.
public async Task<IActionResult> CreateOrder([FromBody] TicketSales Sales)
{
System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
string razorkey = "key";
string secret = "secret";
RazorpayClient client = new RazorpayClient(razorkey, secret);
Dictionary<string, object> options = new Dictionary<string, object>();
options.Add("amount", Sales.subTotal.Replace(".", "")); // amount in the smallest currency unit
options.Add("receipt", "Receipt_567");
options.Add("currency", "INR");
options.Add("payment_capture", "0");
Order order = client.Order.Create(options);
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("https://api.razorpay.com/v1/checkout/embedded");
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("key",razorkey),
new KeyValuePair<string, string>("Amount", Sales.subTotal),
new KeyValuePair<string, string>("currency", "INR"),
new KeyValuePair<string, string>("name",Sales.bName),
new KeyValuePair<string, string>("description","Test Transaction"),
new KeyValuePair<string, string>("imag", ""),
new KeyValuePair<string, string>("order_id",Convert.ToString(order["id"])),
new KeyValuePair<string, string>("callback_url","localhost:4200//signin"),
});
var result = await httpClient.PostAsync("https://api.razorpay.com/v1/checkout/embedded", content);
if (result.IsSuccessStatusCode)
{
}
}
return Json(new { orderId = order["id"].ToString(),result });
}
check razorpay .net reference here
you have to post the error then someone may give you the solution!
For JavaScript client, you should consider the following flow while using asp.net core,
I have used it with the React.js client but you can find some similarities and make it work for the Angular.
This is the official documentation link for javascript client integration with your backend server,
https://razorpay.com/docs/payment-gateway/web-integration/standard/#step-1-create-an-order-from-your-server
This is my React.js client app handler which will be called on button click,
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
const handleRazorpayPayment = () => {
const data = {}; // here anything extra can be passed while creating an order
const response = await axios.post(`api/payment/initialize`, data);
const order_id = response.data.id;
const options = {
key: `razorpay_key`,
amount: 200,
name: 'Your javascript client app',
description: 'Pro Membership',
image: '/your_logo.png',
order_id: order_id,
handler: (response) => {
axios.post(`api/payment/confirm`, response)
.then(response=>alert(response.data))
.catch((err)=>console.log(err))
},
prefill: {
name: "TESTUSER",
email: "testuser#mail.com",
},
theme: {
color: '#F37254'
}
};
const rzp1 = new window.Razorpay(options);
rzp1.open();
};
This is the PaymentController.cs which will create an Order using Razorpay client library,
[Route("api/[controller]")]
[ApiController]
public class PaymentController : ControllerBase
{
private RazorpayClient _razorpayClient;
public PaymentController()
{
_razorpayClient = new RazorpayClient("key", "secret");
}
[HttpPost]
[Route("initialize")]
public async Task<IActionResult> InitializePayment()
{
var options = new Dictionary<string, object>
{
{ "amount", 200 },
{ "currency", "INR" },
{ "receipt", "recipt_1" },
// auto capture payments rather than manual capture
// razor pay recommended option
{ "payment_capture", true }
};
var order = _razorpayClient.Order.Create(options);
var orderId = order["id"].ToString();
var orderJson = order.Attributes.ToString();
return Ok(orderJson);
}
public class ConfirmPaymentPayload
{
public string razorpay_payment_id { get; }
public string razorpay_order_id { get; }
public string razorpay_signature { get; }
}
[HttpPost]
[Route("confirm")]
public async Task<IActionResult> ConfirmPayment(ConfirmPaymentPayload confirmPayment)
{
var attributes = new Dictionary<string, string>
{
{ "razorpay_payment_id", confirmPayment.razorpay_payment_id },
{ "razorpay_order_id", confirmPayment.razorpay_order_id },
{ "razorpay_signature", confirmPayment.razorpay_signature }
};
try
{
Utils.verifyPaymentSignature(attributes);
// OR
var isValid = Utils.ValidatePaymentSignature(attributes);
if (isValid)
{
var order = _razorpayClient.Order.Fetch(confirmPayment.razorpay_order_id);
var payment = _razorpayClient.Payment.Fetch(confirmPayment.razorpay_payment_id);
if (payment["status"] == "captured")
{
return Ok("Payment Successful");
}
}
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError);
}
return StatusCode(StatusCodes.Status500InternalServerError);
}
}

Web API translate JSON object into simple parameters

If I am sending JSON data (via POST) to a .Net Core Web API like this
{ a: "a", b: "b" }
What do I need to do to have a controller method like this?
[HttpPost]
public async Task SometMethod(string a, string b)
{
return Ok();
}
Normally, all tutorials and docs say that you need to define a class and use [FromBody] attribute. But how can I make do without extra classes that I don't really need?
Firstly,your json should be:
{
"a":"a",
"b":"b"
}
You could receive data as JObject instead of a class like below:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpPost]
public void Post(JObject data)
{
//get the property value like below
var data1 = data["a"].ToString();
var data2 = data["b"].ToString();
}
}
Result (For easily distinguish value and property name,I change a to aaa and b to bbb):
If you want to post the data to the method like this, you will have to serialize your data before you can send it to the server. Assuming you are using JQuery, you can do like the following.
var postData = $.param({ a: "a", b: "b" });
//Then you can send this postData obejct to the server. This should perfectly bound to the parameters.
You can also use the same in an angular app.
After some research I came up with ModelBinder to do just this. It is not performant since it re-parses the whole request body for every parameter. I will improve it in the future.
https://github.com/egorpavlikhin/JsonParametersModelBinder
public class JsonBinder : IModelBinder
{
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));
var actionDescriptor = bindingContext.ActionContext.ActionDescriptor as ControllerActionDescriptor;
if (actionDescriptor.MethodInfo.GetCustomAttributes(typeof(JsonParametersAttribute), false).Length > 0)
{
var context = bindingContext.HttpContext;
if (context.Request.ContentType != "application/json")
{
bindingContext.Result = ModelBindingResult.Failed();
return;
}
#if (NETSTANDARD2_1 || NETCOREAPP3_0)
context?.Request.EnableBuffering();
#else
context?.Request.EnableRewind();
#endif
using var reader = new StreamReader(context.Request.Body, Encoding.UTF8,
false,
1024,
true); // so body can be re-read next time
var body = await reader.ReadToEndAsync();
var json = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(body);
if (json.TryGetValue(bindingContext.FieldName, out var value))
{
if (bindingContext.ModelType == typeof(string))
{
bindingContext.Result = ModelBindingResult.Success(value.GetString());
}
else if (bindingContext.ModelType == typeof(object))
{
var serializerOptions = new JsonSerializerOptions
{
Converters = {new DynamicJsonConverter()}
};
var val = JsonSerializer.Deserialize<dynamic>(value.ToString(), serializerOptions);
bindingContext.Result = ModelBindingResult.Success(val);
}
}
context.Request.Body.Position = 0; // rewind
}
}
}

Issue of getting data from two tables in web Api

i have created a simple API controller and added the following method in it:
public IQueryable<tbl_Book> GetBooks()
{
//AspNetUser user = new AspNetUser();
return _context.tbl_Book;
}
and then i have created an MVC controller to consume this API as follow:
public ActionResult Index()
{
IEnumerable<tbl_Book> books = null;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:57368/api/");
var responseTask = client.GetAsync("Admin");
responseTask.Wait();
var result = responseTask.Result;
if(result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsAsync<IEnumerable<tbl_Book>>();
readTask.Wait();
books = readTask.Result;
}
else
{
ModelState.AddModelError(string.Empty, "Error occured while fetching data from api");
}
}
return View(books);
}
it works just fine and gives the result but i want to get data from two tables which are tbl_Categories and AspNetusers which i do like this:
public IQueryable<tbl_Book> GetBooks()
{
//AspNetUser user = new AspNetUser();
return _context.tbl_Book.Include(x=>x.AspNetUser).Include(x=>x.tbl_Category);
}
book model has foreign keys from tbl_Categories and AspNetUsers but when i try to consume this above API with include functions it gives null result.

Manipulating the received Json Data in Web API Controller

I am passing Json Data from Angular JS Controller. The Json Data contains two strings called name attribute and comment attribute and a list of files. The controller code for angular is given below:
app.controller("demoController", function ($scope, $http) {
//1. Used to list all selected files
$scope.files = [];
//2. a simple model that want to pass to Web API along with selected files
$scope.jsonData = {
name: "Sibnz",
comments: "This is a comment"
};
//3. listen for the file selected event which is raised from directive
$scope.$on("seletedFile", function (event, args) {
$scope.$apply(function () {
//add the file object to the scope's files collection
$scope.files.push(args.file);
});
});
//4. Post data and selected files.
$scope.save = function () {
$http({
method: 'POST',
url: "http://localhost:51739/PostFileWithData",
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
var formData = new FormData();
formData.append("model", angular.toJson(data.model));
for (var i = 0; i < data.files.length; i++) {
formData.append("file" + i, data.files[i]);
}
return formData;
},
data: { model: $scope.jsonData, files: $scope.files }
}).
success(function (data, status, headers, config) {
alert("success!");
}).
error(function (data, status, headers, config) {
alert("failed!");
});
};
});
In the Web API, controller I am receiving the JSON data by using the following code:
[HttpPost]
[Route("PostFileWithData")]
public async Task<HttpResponseMessage> Post()
{
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
var root = HttpContext.Current.Server.MapPath("~/App_Data/Uploadfiles");
Directory.CreateDirectory(root);
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
var model = result.FormData["jsonData"];
var g = result.FileData;
if (model == null)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
//TODO: Do something with the JSON data.
//get the posted files
foreach (var file in result.FileData)
{
//TODO: Do something with uploaded file.
var f = file;
}
return Request.CreateResponse(HttpStatusCode.OK, "success!");
}
When I debug the code, I find that the JSON data is populating the var model and var g variables. I want to extract the name and comment attributes from the Json Data and store them in the Database. And also want to copy the file into /App_Data/Uploadfiles directory and store the file location in the database.
You need to create a model in your Web API and deserialize JSON data to this model, you can use Newtonsoft.Json NuGet package for that
Install-Package Newtonsoft.Json
class DataModel
{
public string name { get; set; }
public string comments { get; set; }
}
In Web API controller
using Newtonsoft.Json;
HttpRequest request = HttpContext.Current.Request;
var model = JsonConvert.DeserializeObject<DataModel>(request.Form["jsonData"]);
// work with JSON data
model.name
model.comments
To work with files
// Get the posted files
if (request.Files.Count > 0)
{
for (int i = 0; i < request.Files.Count; i++)
{
Stream fileStream = request.Files[i].InputStream;
Byte[] fileBytes = new Byte[stampStream.Length];
// Do something with uploaded file
var root = HttpContext.Current.Server.MapPath("~/App_Data/Uploadfiles/");
string fileName = "image.jpg";
File.WriteAllBytes(root + fileName, stampBytes);
// Save only file name to your database
}
}

Web API Typeless OData Service with OWIN self-hosting returns 406 Not Acceptable

I'm trying to set up a Web API Typeless OData Service with OWIN self-hosting... =)
But why not working? :~(
This is some code I have partially extracted from all kinds of examples out there...
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
appBuilder.UseWebApi(config);
}
}
public class Program
{
public static IEdmModel Model = GetEdmModel();
static void Main(string[] args)
{
using (WebApp.Start<Startup>("http://localhost:8080"))
{
Console.WriteLine("Running...");
Console.ReadLine();
}
}
public static IEdmModel GetEdmModel()
{
var model = new EdmModel();
// Create and add product entity type.
var product = new EdmEntityType("NS", "Product");
product.AddKeys(product.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));
product.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String);
product.AddStructuralProperty("Price", EdmPrimitiveTypeKind.Double);
model.AddElement(product);
// Create and add category entity type.
var category = new EdmEntityType("NS", "Category");
category.AddKeys(category.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));
category.AddStructuralProperty("Name", EdmPrimitiveTypeKind.String);
model.AddElement(category);
// Set navigation from product to category.
var propertyInfo = new EdmNavigationPropertyInfo();
propertyInfo.Name = "Category";
propertyInfo.TargetMultiplicity = EdmMultiplicity.One;
propertyInfo.Target = category;
var productCategory = product.AddUnidirectionalNavigation(propertyInfo);
// Create and add entity container.
var container = new EdmEntityContainer("NS", "DefaultContainer");
model.AddElement(container);
// Create and add entity set for product and category.
var products = container.AddEntitySet("Products", product);
var categories = container.AddEntitySet("Categories", category);
products.AddNavigationTarget(productCategory, categories);
return model;
}
}
public class ProductsController : ODataController
{
private static readonly IQueryable<IEdmEntityObject> Products = Enumerable.Range(0, 10).Select(i =>
{
var productType = (IEdmEntityType)Program.Model.FindType("NS.Product");
var categoryType = (IEdmEntityTypeReference)productType.FindProperty("Category").Type;
var product = new EdmEntityObject(productType);
product.TrySetPropertyValue("Id", i);
product.TrySetPropertyValue("Name", "Product " + i);
product.TrySetPropertyValue("Price", i + 0.01);
var category = new EdmEntityObject(categoryType);
category.TrySetPropertyValue("Id", i % 5);
category.TrySetPropertyValue("Name", "Category " + (i % 5));
product.TrySetPropertyValue("Category", category);
return product;
}).AsQueryable();
public EdmEntityObjectCollection Get()
{
// Get Edm type from request.
var path = this.Request.GetODataPath();
var edmType = path.EdmType;
Contract.Assert(edmType.TypeKind == EdmTypeKind.Collection);
var collectionType = edmType as IEdmCollectionType;
var entityType = collectionType.ElementType.Definition as IEdmEntityType;
var model = Request.GetEdmModel();
var queryContext = new ODataQueryContext(model, entityType);
var queryOptions = new ODataQueryOptions(queryContext, Request);
// Apply the query option on the IQueryable here.
return new EdmEntityObjectCollection(new EdmCollectionTypeReference(collectionType, false), Products.ToList());
}
public IEdmEntityObject GetProduct(int key)
{
object id;
var product = Products.Single(p => HasId(p, key));
return product;
}
public IEdmEntityObject GetCategoryFromProduct(int key)
{
object id;
var product = Products.Single(p => HasId(p, key));
object category;
if (product.TryGetPropertyValue("Category", out category))
{
return (IEdmEntityObject)category;
}
return null;
}
public IEdmEntityObject Post(IEdmEntityObject entity)
{
// Get Edm type from request.
var path = Request.GetODataPath();
var edmType = path.EdmType;
Contract.Assert(edmType.TypeKind == EdmTypeKind.Collection);
var entityType = (edmType as IEdmCollectionType).ElementType.AsEntity();
// Do something with the entity object here.
return entity;
}
private bool HasId(IEdmEntityObject product, int key)
{
object id;
return product.TryGetPropertyValue("Id", out id) && (int)id == key;
}
}
The result I get is:
{StatusCode: 406, ReasonPhrase: 'Not Acceptable', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Date: Mon, 12 May 2014 18:08:25 GMT
Server: Microsoft-HTTPAPI/2.0
Content-Length: 0
}}
From running this:
var client = new HttpClient();
var response = client.GetAsync("http://localhost:8080/api/Products").Result;
If you are using OData V4, you need to make a change in your controller:
Old:
using System.Web.Http.OData;
New:
using System.Web.OData;

Resources