I am a starter in Azure Functions and durable Entities. I want to do the following things:
Create a durable entity and it has a state called systemList;
Create a queue trigger function to consume messages in my queue and store them in the entity state I just created.
create a http trigger function to get the current state of the entity;
And I met some problems in the 3rd step.
The code is as follows:
//HttpTriggerFunction.cs:
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using System.Net.Http;
using System.Net;
using Newtonsoft.Json.Linq;
namespace **.Function
{
public static class HttpTriggerQueryEntity
{
[FunctionName("QueryEntity")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function)] HttpRequestMessage req,
[DurableClient] IDurableEntityClient client)
{
var entityId = new EntityId(nameof(ProcessingListEntity), "processing_message_total");
EntityStateResponse<JObject> stateResponse = await client.ReadEntityStateAsync<JObject>(entityId);
//await client.SignalEntityAsync(entityId, "Empty");
return req.CreateResponse(HttpStatusCode.OK,stateResponse.EntityState);
}
}
}
//blockData.cs
#nullable enable
using System;
namespace **.Function
{
public class BlockData
{
public string? id { get; set; }
public string? SessionId { get; set; }
public string? MachineId { get; set; }
public DateTime? Start { get; set; }
public DateTime? End { get; set; }
public string? Activity {get; set;}
public string? BlobId { get; set; }
}
}
//Entity.cs
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs;
using Newtonsoft.Json;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using System.Collections.Generic;
namespace **.Function
{
[JsonObject(MemberSerialization.OptIn)]
public class ProcessingListEntity
{
public ProcessingListEntity(){
systemList = new Dictionary<string, BlockData>();
}
[JsonProperty("systemList")]
public Dictionary<string, BlockData> systemList {get; set;}
public void Add(BlockData blockData) {
if (!this.systemList.ContainsKey(blockData.MachineId)) {
this.systemList.Add(blockData.MachineId, blockData);
return;
}
else {
this.systemList[blockData.MachineId].Start = blockData.Start;
this.systemList[blockData.MachineId].End = blockData.End;
}
}
public void Empty() => this.systemList = new Dictionary<string, BlockData>();
public Dictionary<string, BlockData> Get() => this.systemList;
[FunctionName(nameof(ProcessingListEntity))]
public static Task Run([EntityTrigger] IDurableEntityContext ctx)
=> ctx.DispatchAsync<ProcessingListEntity>();
}
}
But when I run it in my local environment and send Http query to it, the program stop. But when I changed the following line in HttpTriggerFunction.cs:
return req.CreateResponse(HttpStatusCode.OK,stateResponse.EntityState);
to
return req.CreateResponse(HttpStatusCode.OK,stateResponse.EntityState + "");
It can run and return the required string. But what I want to return is Json string.
So what can I do to fix my code? Thank you!
You can do is serialize the object and encode it and then send it.
So instead of createResponse return a HttpResponseMessage.
First you need to add packages such as:
using system.text;
using NewtonSoft.Json;
Then you can return :
return new HttpResponseMessage(HttpStatusCode.OK){Content = new StringContent(JsonConvert.SerializeOject(stateResponse.EntityState , Formating.Indented),Encoding.UTF8,"Response.json")}:
Refer the following article by Callon Campbell
Refer the following documentation.
Related
I am trying to connect a new Blazor app I have to a REST API created through Django. However I am unable to create the services file as it appears with the error. How should I change BlogPost.cs so that it connects to the API?
Cannot implicitly convert type 'Starter.PostModels.Post[]' to 'System.Collections.Generic.IEnumerable<Starter.UI.Services.BlogPost>' [Starter]"
Starter/Services/BlogPost.cs
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Json;
namespace Starter.UI.Services
{
public class BlogPost : IBlogPost
{
private readonly HttpClient httpClient;
public BlogPost(HttpClient httpClient)
{
this.httpClient = httpClient;
}
public async Task<IEnumerable<BlogPost>> GetPosts()
{
return await httpClient.GetFromJsonAsync<Post[]>("http://127.0.0.1:8000/api/");
}
}
}
Starter/Services/IBlogPost.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Starter.UI.Services
{
public interface IBlogPost
{
Task<IEnumerable<BlogPost>> GetPosts();
}
}
Starter/Models/Post.cs
using System;
namespace Starter.PostModels
{
public class Post
{
public string title { get; set; } = default!;
public string author { get; set; } = default!;
public string content { get; set; } = default!;
public string status { get; set; } = default!;
}
}
Starter/Pages/Blog.razor
#page "/blog"
#using Starter.PostModels'
#using Starter.UI.Services
#inject IBlogPost GetPosts;
<h1>Blog Posts</h1>
#code{
private IEnumerable<Post> Data = null;
protected override async Task OnInitializedASync()
{
await base.OnInitializedAsync();
Data = await IBlogPost.GetPosts();
}
}
You are trying to Post[] to a IEnumerable
public async Task<IEnumerable<BlogPost>> GetPosts()
{
return await httpClient.GetFromJsonAsync<Post[]>("http://127.0.0.1:8000/api/");
}
Try this
public async Task<IEnumerable<Post>> GetPosts()
{
return await httpClient.GetFromJsonAsync<IEnumerable<Post>>("http://127.0.0.1:8000/api/");
}
I am attempting to return the Json response deserialized from the following https://www.supremenewyork.com/mobile_stock.json
Below is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Text;
using System.Drawing;
using System.IO;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using RestSharp;
using System.Threading.Tasks;
using System.Globalization;
namespace SupremeMobileMonitor
{
class Program
{
static async Task Main(string[] args)
{
var program = new Program();
await program.GetItem();
}
// Declaring variables in the list
static List<ItemDetail> ProductList = new List<ItemDetail>();
List<string> productDesc = new List<string> { "new_item", "price", "category", "imageurl", "itemURL" };
List<string> category = new List<string> { "jackets", "shirts", "tops_sweaters", "pants", "hats", "accessories", "shoes", "skate" };
//creating a class for intializing Json Deserializer
public class MobileStockResponse
{
[JsonProperty("unique_image_url_prefixes")]
public List<object> UniqueImageUrlPrefixes { get; set; }
[JsonProperty("products_and_categories")]
public Dictionary<string, List<ProductsAndCategory>> ProductsAndCategories { get; set; }
[JsonProperty("release_date")]
public string ReleaseDate { get; set; }
[JsonProperty("release_week")]
public string ReleaseWeek { get; set; }
}
public partial class ProductsAndCategory
{
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("image_url")]
public string ImageUrl { get; set; }
[JsonProperty("image_url_hi")]
public string ImageUrlHi { get; set; }
[JsonProperty("price")]
public long Price { get; set; }
[JsonProperty("sale_price")]
public long SalePrice { get; set; }
[JsonProperty("new_item")]
public bool NewItem { get; set; }
[JsonProperty("position")]
public long Position { get; set; }
[JsonProperty("category_name")]
public string CategoryName { get; set; }
}
//Initializing HttpClient for Requests and po
public async Task GetItem()
{
var client = new HttpClient();
var request = new HttpRequestMessage
{
RequestUri = new Uri("https://www.supremenewyork.com/mobile_stock.json"),
Method = HttpMethod.Get
};
var response = await client.SendAsync(request);
var responseContent = await response.Content.ReadAsStringAsync();
var responseObject = JsonConvert.DeserializeObject<ProductsAndCategory>(responseContent);
Console.WriteLine(responseObject);
}
}
}
When I try to return a value (example: responseObject.id) It will just return '0'
When I try to return the complete response, it returns "SupremeMobileMonitor.Program+ProductsAndCategory"
Any idea why I can't get it returned and what I'm messing up my deserialization? Unfortunately the category known as "new" on the endpoint interferes with the C# keywords therefore removing my option to use dynamic deserialization.
jslowik has the correct answer for your question, how to deserialize it.
To Print the object, you can either create an override ToString() method and print out only the things you are interested in, or you can print the object by serializing it to a string.
Console.WriteLine(JsonConvert.SerializeObject(productsAndCategories, Formatting.Indented);
This will give you a json representation again of the object and show you all the values.
SideNote: If you want to get specific items from, Say, Bags, you can use Linq to get it...
Console.WriteLine(JsonConvert.SerializeObject(responseObject.ProductsAndCategories["Bags"].Select(x => x.Id)));
// Output:
[173389,172978,173019,172974,173018,173001]
Off hand I would just deserialize the full object. Example:
// Full model represented by your class
var responseObject = JsonConvert.DeserializeObject<MobileStockResponse>(responseContent);
// The products and categories dictionaries you're looking for
var productsAndCategories = responseObject.ProductsAndCategories;
The overall goal is to be able to perform a lookup of a meal based on the userid, and mealid. If that item is found, I want to be able to delete only the entire element that matches both the userid and mealid.
Currently, After sending the request object via postman in a post request, I have tried to write a variation of queries using the C# to create a builder object, and then filter to find the specific array object, and finally delete the array object if there is a match on both userid and mealid. Initially, I was getting the issue where the entire element was not being deleted, but only the interal array element that is nested inside of the element was being (not deleted, but set back to null values). However, now the issue is that the entire array element is not being deleted at all and i'm getting the following error.
BsonArraySerializer Error from Visual Studio
Can someone please help me to resolve this issue?
Here is a sample object that I'm sending via postman that I'm trying to delete:
Sample Postman POST request with Body data
Here is an example image of data that I'm trying to delete:
Sample Image of Json Array Elemet I'm trying to delete
You will need MongoDb Compass or Atlas, .NET Core 3.1, MongoDB C# Driver 2.0, Postman, and .NET Core 3.1 WebApi Project/Solution in order to help solve this issue.
Below, is the code that is needed to replicate the issue:
Startup.cs
Add this line of code to the Configuration method of this file
services.AddScoped<IMealsRepository, MealsRepository>();
Add this line to the ConfigureServices Method
services.AddSingleton(sp =>
sp.GetRequiredService<IOptions<DatabaseSettings>>().Value);
appSettings.json
Add these lines of code to this file
"DatabaseSettings": {
"ConnectionString": "your connection string to MongoDb"
}
Database Settings.cs
public class DatabaseSettings
{
public string ConnectionString { get; set; }
}
MealPlanModel.cs:
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
public class MealPlanModel
{
#region MealPlanModel fields
[BsonElement("userid")]
public int? UserId { get; set; }
[BsonElement("mealid")]
public int? MealId { get; set; }
[BsonElement("mealname")]
public string MealName { get; set; }
[BsonElement("mealimage")]
public string MealImage { get; set; }
[BsonElement("foods")]
public FoodModel[] Foods { get; set; }
[BsonElement("totalcalories")]
public double TotalCalories { get; set; }
[BsonElement("totalprotein")]
public double TotalProtein { get; set; }
[BsonElement("totalcarbs")]
public double TotalCarbs { get; set; }
[BsonElement("totalfat")]
public double TotalFat { get; set; }
[BsonElement("totalsugar")]
public double TotalSugar { get; set; }
[BsonElement("totalfiber")]
public double TotalFiber { get; set; }
#endregion
#region MealPlanModel ctor
public MealPlanModel()
{
}
public MealPlanModel(int userid, int mealid)
{
UserId = userid;
MealId = mealid;
}
}
MealPlanDto.cs
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System.Collections.Generic;
public class MealPlanDto
{
[BsonId]
public ObjectId Id { get; set; }
[BsonElement("meals")]
public List<MealPlanModel> MealPlans { get; set; }
}
**MealsController.cs:**
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
[Route("api/[controller]")]
[ApiController]
public class MealsController : ControllerBase
{
private readonly IMealsRepository _repo;
private readonly IMapper _mapper;
public MealsController(IMealsRepository repo, IMapper mapper)
{
_repo = repo;
_mapper = mapper;
}
[HttpGet, Route("CheckConnection")]
public async Task<IActionResult> CheckConnection()
{
var result = await _repo.CheckConnection();
if (result == null || result.Count <= 0)
return BadRequest("Failed to connect to database.");
return Ok("Database connection was successful");
}
[HttpPost("deletecustommeal")]
public async Task<IActionResult> DeleteCustomMealPlan(int id)
{
var requestBody = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
var mealPlanToDelete = JsonConvert.DeserializeObject<MealPlanModel>(requestBody);
MealPlanDto deleteMealPlan = new MealPlanDto();
deleteMealPlan.MealPlans = new List<MealPlanModel>();
deleteMealPlan.MealPlans.Add(mealPlanToDelete);
var result = await _repo.DeleteCustomMealPlanById(deleteMealPlan);
if (!result)
return BadRequest("Failed to delete meal");
return Ok("Successfully deleted meal plan");
}
}
MealsRepository.cs
using Microsoft.Extensions.Configuration;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public class MealsRepository : IMealsRepository
{
private readonly MongoClient _client;
private readonly IMongoDatabase _database;
private readonly IMongoCollection<MealPlanDto> _userMealsCollection;
public MealsRepository(IConfiguration configuration)
{
_client = new
MongoClient(configuration.GetSection("DatabaseSettings").GetSection("ConnectionString").Value);
_database = _client.GetDatabase("MealsDb");
_userMealsCollection = _database.GetCollection<MealPlanDto>("meal");
}
public async Task<List<BsonDocument>> CheckConnection()
{
List<BsonDocument> list = await _database.ListCollections().ToListAsync();
var populatedList = (list != null && list.Count > 0) ? list : null;
return populatedList;
}
public async Task<bool> DeleteCustomMealPlanById(MealPlanDto mealPlanToDelete)
{
var builder = Builders<MealPlanDto>.Filter;
var filter = builder.Eq(x => x.MealPlans[0].UserId, mealPlanToDelete.MealPlans[0].UserId);
var update = Builders<MealPlanDto>.Update.PullFilter(
p => (IEnumerable<MealPlanModel>)p.MealPlans[0],
f => f.MealId.Value == mealPlanToDelete.MealPlans[0].MealId);
try
{
await _userMealsCollection.UpdateOneAsync(filter, update);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Failed to delete meal plan. {ex} occured.");
return false;
}
}
}
Thanks for all that attempted to find an answer to my question above, but I actually discovered a simple solution
I simply replaced the above method in the Repository.cs file with the following and it works like a charm
public bool DeleteCustomMealPlanForUserById(MealPlanModel mealPlanToDelete)
{
var result = _customUserMealsCollection.DeleteOne(p => p.MealPlans[0].UserId == mealPlanToDelete.UserId
&& p.MealPlans[0].MealId == mealPlanToDelete.MealId);
return result.DeletedCount != 0;
}
I'm trying Firestore with the nugget package Google.Cloud.Firestore
I followed this intro CRUD with firestore
Using the debugger I can see that the execution of the program stops when trying to call the method Query.GetSnapshotAsync()
I want to get just a list of documents from a collection.
Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http;
using System.Web.Http.Results;
using FirestoreAPI.Domain.Restaurants;
using FirestoreAPI.Repository.Restaurants;
using System.Threading.Tasks;
namespace FirestoreAPI.Controllers
{
[RoutePrefix("api")]
public class RestaurantsController : ApiController
{
public RestaurantsController() { }
[HttpGet]
[Route("restaurants")]
public IHttpActionResult GetAllRestaurants()
{
//var restAggregate = new RestaurantsAggregate();
var restaurantsRepo = new RestaurantsRepo();
return new NegotiatedContentResult<Task<List<Restaurant>>>(
HttpStatusCode.OK,
restaurantsRepo.GetAllRestaurants(),
this
); ;
}
}
}
DataLayer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Google.Cloud.Firestore;
namespace FirestoreAPI.Repository.Restaurants
{
public class RestaurantsRepo
{
//public FirestoreConn dbConn;
string projectId;
FirestoreDb firestoreDb;
public RestaurantsRepo()
{
//dbConn = new FirestoreConn();
string credentials = "C:\\Users\\ezequiel.lopez\\projects\\firestoredotnet\\FirestoreAPI\\firestoreapi-dca55-0be2f7d57f41.json";
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", credentials);
projectId = "firestoreapi-dca55";
firestoreDb = FirestoreDb.Create(projectId);
}
public async Task<List<Restaurant>> GetAllRestaurants()
{
//FirestoreDb fsDB = dbConn.GetFSConnection();
//Query query = fsDB.Collection("restaurants").OrderByDescending("avgRating").Limit(50);
Query query = firestoreDb.Collection("restaurants").OrderByDescending("avgRating").Limit(50);
QuerySnapshot restSnaps = await query.GetSnapshotAsync();
List<Restaurant> restaurants = new List<Restaurant>();
return restSnaps.Documents
.Where<DocumentSnapshot>(ds => ds.Exists)
.Select(ds => ds.ConvertTo<Restaurant>()).ToList();
}
}
}
Restaurant
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Google.Cloud.Firestore;
namespace FirestoreAPI.Repository.Restaurants
{
[FirestoreData]
public class Restaurant
{
[FirestoreProperty]
public decimal avgRating { get; set; }
[FirestoreProperty]
public string category { get; set; }
[FirestoreProperty]
public string city { get; set; }
[FirestoreProperty]
public string name { get; set; }
[FirestoreProperty]
public int numRatings { get; set; }
[FirestoreProperty]
public int price { get; set; }
}
}
I was having the same issue. Thing is, I was calling an async method from a synchronous one. It didn't work until I've made my caller method async and awaited for it.
I just started off with programming in C#. I'm using Visual Studio to make a Mongo database and followed a tutorial to get the following:
using System;
using System.Collections.Generic;
using System.Text;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace NetCoreWeb.Repositories
{
public class BreakoutStrategyConfig
{
[BsonElement("id")]
public ObjectId id { get; set; }
[BsonElement("stock")]
public string stock { get; set; }
[BsonElement("trade_limit")]
public int trade_limit { get; set; }
[BsonElement("interval")]
public double interval { get; set; }
[BsonElement("exit_pl")]
public double exit_pl { get; set; }
}
}
This is the implementation:
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using MongoDB.Bson;
using MongoDB.Driver;
namespace NetCoreWeb.Repositories
{
public class BreakoutStrategyConfigImpl : IBreakoutStrategyConfig
{
private readonly IMongoDatabase _db;
public BreakoutStrategyConfigImpl()
{
MongoClient client = new MongoClient("mongodb://mymongo:27017");
_db = client.GetDatabase("BreakoutStrategyConfig");
}
public ICollection<BreakoutStrategyConfig> GetAllBreakoutStrategyConfigs()
{
List<BreakoutStrategyConfig> configs = new List<BreakoutStrategyConfig>();
var cursor = _db.GetCollection<BreakoutStrategyConfig>("BreakoutStrategyConfigs").Find(new BsonDocument()).ToCursor();
foreach (var document in cursor.ToEnumerable())
{
configs.Add(document);
}
return configs;
}
public BreakoutStrategyConfig GetBreakoutStrategyConfigById(ObjectId id)
{
return _db.GetCollection<BreakoutStrategyConfig>("BreakoutStrategyConfigs").Find(config => config.id == id).FirstOrDefault();
}
public void AddBreakoutStrategyConfig(BreakoutStrategyConfig config)
{
_db.GetCollection<BreakoutStrategyConfig>("BreakoutStrategyConfigs").InsertOne(config);
}
public void DeleteBreakoutStrategyConfig(ObjectId id)
{
_db.GetCollection<BreakoutStrategyConfig>("BreakoutStrategyConfigs").DeleteOne(config => config.id == id);
}
public void UpdateBreakoutStrategyConfig(BreakoutStrategyConfig config)
{
_db.GetCollection<BreakoutStrategyConfig>("BreakoutStrategyConfigs").ReplaceOneAsync(n => n.id.Equals(config.id)
, config
, new UpdateOptions { IsUpsert = true });
}
}
}
My problem is pretty simple: I made the classes and tables but I'm not sure how to test this.
How can I see a list of collections a documents in the database?
Do I write a script in Program.cs (automatically created)?
Essentially, I just need to see if this works.
Did you mean that collection and database is created by your code or not?
if yes, you don't need to manually run the script to create db and collection.
If DB / collection is not exist then mongodb will automatically creates it.