WEB API .NET 5 Stream JSON objects to the client fetch request - asp.net-core-webapi

With the following source code I am able to stream JSON objects via ASP.NET Web API, that's fine & cool !
I would like to migrate this source code to .NET 5. Since PushStreamContent class is not provided any more, Can anyone help me to facing with solution ? Any reference or examples are kindly accepted.
Mersi
using Newtonsoft.Json;
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace WebApplication1.Controllers
{
public class ValuesController : ApiController
{
[HttpGet]
public HttpResponseMessage GetMultipartData()
{
var response = new HttpResponseMessage();
var content = new PushStreamContent(new Action<Stream, HttpContent, TransportContext>(WriteContent), "application/json");
response.Headers.TransferEncodingChunked = true;
response.Content = content;
return response;
}
public static void WriteContent(Stream stream, HttpContent content, TransportContext context)
{
var serializer = JsonSerializer.CreateDefault();
using (var sw = new StreamWriter(stream))
using (var jw = new JsonTextWriter(sw))
{
jw.WriteStartArray();
foreach (var id in Enumerable.Range(1, 100000))
{
serializer.Serialize(jw, new TestModel()
{
Alias = "rvhuang",
BirthDate = new DateTime(1985, 02, 13),
FirstName = "Robert",
LastName = "Huang",
ID = id,
MiddleName = "Vandenberg",
});
}
jw.WriteEndArray();
}
}
}
public class TestModel
{
public string FirstName
{
get; set;
}
public string MiddleName
{
get; set;
}
public DateTime BirthDate
{
get; set;
}
public string LastName
{
get; set;
}
public string Alias
{
get; set;
}
public int ID
{
get; set;
}
}
}

Related

Xamarin Forms Sqlite UpdateAsync updating database

Xamarin Forms 5
VS2019
Currently trying to update android only.
I've tried several different ways to update the database, but nothing seems to work. It seems to be updating cache, because if I select the same entry it has the changes, but even the ObservableCollection isn't being updated.
Here's the latest:
Model
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using static Android.Resource;
#nullable disable
namespace Photography.Handbook.Models
{
public partial class Aperture : INotifyPropertyChanged
{
public Aperture()
{
}
//public Aperture()
//{
// ShutterApertures = new HashSet<ShutterAperture>();
//}
[PrimaryKey]
[Key]
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
public string Notes { get; set; }
[OneToMany(CascadeOperations = CascadeOperation.All)]
public virtual ICollection<ShutterAperture> ShutterApertures { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Update Code
public async Task UpdateAsync(Aperture entity)
{
String databasePath = await DB.GetDatabaseFilePath();
SQLiteAsyncConnection db = new SQLiteAsyncConnection(databasePath);
var x = App.db.DBInstance.Query<Aperture>($"SELECT * FROM Aperture WHERE Id = '{entity.Id}'");
if(x != null)
{
x[0].Name = entity.Name;
x[0].Active = entity.Active;
x[0].Notes = entity.Notes;
var y = await db.UpdateAllAsync(x[0]);
}
}
Found the problem. I was overwriting the database each time I re-started the app.
Thanks everyone for the suggestions.

Create a LINQ query to check to see if the data in the database exists?

I'm using ASP.NET core and Testing it with Postman WebAPI.
I'm trying to work out the LINQ query which makes it impossible for the user to post the same data if Title and request contains string of “Hope" and "Something" within the database. How do you create a query so when the user posts the same string within the same attributes, it displays a bad request?
As I'm directly doing this in the controller do you need a repository?
Below is my controller and All I need is to be able to query the title attribute and to query it out so only the user enters different string in the database. I've tested it out with postman and it shows 200OK which should show Bad Request when entering the same string in Postman
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using BookingApp.API.Data;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using BookingApp.API.Models;
using Microsoft.EntityFrameworkCore;
namespace BookingApp.API.Controllers
{
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class BookController : ControllerBase
{
private readonly DataContext _context;
public BookController(DataContext context)
{
_context = context;
}
[AllowAnonymous]
[HttpGet]
public async Task<IActionResult> GetBooking()
{
var Booking = await _context.bookings.Include(c => c.Customer).ToListAsync();
return Ok(Booking);
}
[AllowAnonymous]
[HttpGet("{id}")]
public async Task<IActionResult> GetBooking(int id)
{
var Booking = await _context.bookings.FirstOrDefaultAsync(x => x.Id == id);
return Ok(Booking);
}
[AllowAnonymous]
[HttpPost]
public async Task<IActionResult> PostBook(Booking bookings, string Title)
{
if(ModelState.IsValid)
{
var SearchData = await _context.bookings.Where(x => x.Title == Title).SingleOrDefaultAsync();
if (SearchData != null)
return BadRequest("bad request");
}
_context.bookings.Add(bookings);
_context.SaveChanges();
return Ok();
}
// PUT api/values/5
// [HttpPut("{id}")]
[AllowAnonymous]
[HttpPut("{Id}")]
public Booking PutBooking(int Id, [FromBody] Booking bookings )
{
var bookingsInDb = _context.bookings.SingleOrDefault(b => b.Id == Id);
bookingsInDb.Title = bookings.Title;
bookingsInDb.Date = bookings.Date;
bookingsInDb.Request = bookings.Request;
_context.SaveChanges();
return bookingsInDb;
}
//
//
// }
{
}
}
}
This is my model of the Booking
using System;
namespace BookingApp.API.Models
{
public class Booking
{
public int Id { get; set; }
public string Title { get; set; }
public DateTime Date { get; set; }
public string Request { get; set; }
public int NoPeople { get; set; }
public Customer Customer { get; set;}
}
}

asp.net json string to de-serialize into varibales

I'm new to json and I need help with following json string, I need to fetch values into string variables to save into db.
{
"message_id": {"8624389": "447123456789"},
"sent_text": "Test message",
"parts_count": 1
}
how can I get values of message_id, sent_text and parts_count into variables?
Thanks
I use this website:https://app.quicktype.io/
It uses newtonsoft nuget package. With a little tweaking it saves alot of time.
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
// using MyNamespace;
//
// var myObject = MyObject.FromJson(jsonString);
namespace MyNamespace
{
using System;
using System.Net;
using System.Collections.Generic;
using Newtonsoft.Json;
public partial class MyObject
{
[JsonProperty("message_id")]
public MessageId MessageId { get; set; }
[JsonProperty("sent_text")]
public string SentText { get; set; }
[JsonProperty("parts_count")]
public long PartsCount { get; set; }
}
public partial class MessageId
{
[JsonProperty("8624389")]
public string The8624389 { get; set; }
}
public partial class MyObject
{
public static MyObject FromJson(string json) => JsonConvert.DeserializeObject<MyObject>(json, MyNamespace.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this MyObject self) => JsonConvert.SerializeObject(self, MyNamespace.Converter.Settings);
}
public class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
};
}
}

Add tags to talk for many to many relationship in Entity Framework

I am creating an API endpoint that creates a new Talk with the tags that should be associated to the talk. I have a many to many relationship set up between tags and talks in my domain, see below for the relationship.
Tag.cs
using System;
using System.Collections.Generic;
namespace Conferency.Domain
{
public class Tag : IAuditable
{
public int Id { get; set; }
public string Name { get; set; }
public List<TalkTag> TalkTags { get; set; }
public DateTime ModifiedAt { get; set; }
public DateTime CreatedAt { get; set; }
}
}
Talk.cs
using System;
using System.Collections.Generic;
namespace Conferency.Domain
{
public class Talk : IAuditable
{
public int Id { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public List<TalkTag> TalkTags { get; set; }
public DateTime Presented { get; set; }
public DateTime ModifiedAt { get; set; }
public DateTime CreatedAt { get; set; }
}
}
TalkTag.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace Conferency.Domain
{
public class TalkTag
{
public int TalkId { get; set; }
public Talk Talk { get; set; }
public int TagId { get; set; }
public Tag Tag { get; set; }
}
}
ConferencyContext.cs (Deleted irrelevant code)
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using System;
using Conferency.Domain;
namespace Conferency.Data
{
public class ConferencyContext: DbContext
{
public DbSet<Talk> Talks { get; set; }
public DbSet<Tag> Tags { get; set; }
public DbSet<TalkTag> TagTalks { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TalkTag>()
.HasKey(s => new { s.TalkId, s.TagId });
modelBuilder.Entity<TalkTag>()
.HasOne(pt => pt.Talk)
.WithMany(p => p.TalkTags)
.HasForeignKey(pt => pt.TalkId);
modelBuilder.Entity<TalkTag>()
.HasOne(pt => pt.Tag)
.WithMany(t => t.TalkTags)
.HasForeignKey(pt => pt.TagId);
base.OnModelCreating(modelBuilder);
}
}
}
TalkViewModel.cs
using System;
using System.Collections.Generic;
namespace Conferency.Application.Models
{
public class TalkViewModel
{
public string Name { get; set; }
public string Url { get; set; }
public List<String> Tags { get; set; }
}
}
The problem is I can't figure out how to create a talk and its tags (attach if they exists, create if they don't). I am not sure in what order to accomplish this. Do I have to query each tag to check if they exist or is there a findOrCreate method I could use? How do I create a TalkTag record if the Talk isn't created yet? Is there an elegant way to accomplish this that I am not understanding?
TalkRepository.cs
using System.Collections.Generic;
using Conferency.Domain;
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Conferency.Data
{
public class TalkRepository : ITalkRepository
{
private ConferencyContext _context;
public TalkRepository(ConferencyContext context)
{
_context = context;
}
public void Add(Talk entity)
{
_context.Add(entity);
}
public void AddWithTags(Talk entity, List<String> tags)
{
// Create Talk
// Query for each tag
// Create if they don't exist
// Attach to talk
// ??
}
public IEnumerable<Talk> GetAllTalks()
{
return _context.Talks
.Include(c => c.TalkTags)
.OrderBy(c => c.Presented)
.ToList();
}
public Talk GetTalk(int id)
{
return _context.Talks
.Include(c => c.TalkTags)
.Where(c => c.Id == id)
.FirstOrDefault();
}
public async Task<bool> SaveAllAsync()
{
return (await _context.SaveChangesAsync()) > 0;
}
}
}
I am new to c# and I'm trying to learn best practices and familiarizing myself with EF and ASP.NET Core so hopefully somebody can help guide me in the right path. The full solution is here if you want to take a look https://github.com/bliitzkrieg/Conferency
I tried solving it myself but Im getting a NullPointerException, here is my attempt at a solution:
TalksController.cs
[HttpPost()]
public async Task<IActionResult> Post([FromBody]TalkViewModel model)
{
try
{
_logger.LogInformation("Creating a new Talk");
List<Tag> tags = _tagRepo.FindOrCreateTags(model.Tags);
Talk talk = new Talk { Name = model.Name, Url = model.Url };
List<TalkTag> talkTags = new List<TalkTag>();
tags.ForEach(tag =>
{
var talkTag = new TalkTag { TagId = tag.Id, Talk = talk };
talkTags.Add(talkTag);
});
talk.TalkTags.AddRange(talkTags); // Exception being thrown here
_repo.Add(talk);
if (await _repo.SaveAllAsync())
{
string newUri = Url.Link("TalkGet", new { id = talk.Id });
return Created(newUri, talk);
}
else
{
_logger.LogWarning("Could not save Talk");
}
}
catch (Exception ex)
{
_logger.LogError($"Threw exception while saving Talk: {ex}");
}
return BadRequest();
}
}
TagRepository.cs
using System;
using System.Collections.Generic;
using Conferency.Domain;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using System.Linq;
namespace Conferency.Data
{
public class TagRepository: ITagRepository
{
private ConferencyContext _context;
public TagRepository(ConferencyContext context)
{
_context = context;
}
public void Add(Tag entity)
{
_context.Add(entity);
}
public List<Tag> FindOrCreateTags(List<string> tags)
{
List<Tag> _tags = new List<Tag>();
tags.ForEach(t =>
{
try
{
var tag = _context.Tags
.Where(c => c.Name == t)
.FirstOrDefault();
if (tag != null)
{
_tags.Add(tag);
}
else
{
Tag created = new Tag { Name = t };
this.Add(created);
_tags.Add(created);
}
}
catch (Exception ex)
{
}
});
return _tags;
}
public async Task<bool> SaveAllAsync()
{
return (await _context.SaveChangesAsync()) > 0;
}
}
}
On your TalkViewModel add a List<TagViewModel> property with the following properties:
public int TagId { get; set; }
public string TagName { get; set; }
public bool Selected { get; set; }
When you pass the TalkViewModel to your repo, filter out the selected TagViewModels and for each one, add a TalkTag with the proper TagId to your TalkTags property on your Talk. EF should take care of adding the proper TalkId upon _context.SaveChanges().
If the Tag doesn't exist, create a TalkTag with a new Tag and the new Talk as its properties, then add it to your _context. EF should take care of the rest.
You haven't initialized your TalkTags collection which causes the nullpointer. Try this when initializing the Talk object:
Talk talk = new Talk { Name = model.Name, Url = model.Url, TalkTags = new List<TalkTag>() };
Do you need more properties on a TalkTag object? Otherwise you could just have List<Talk> in the Tag class and List<Tag> in the Talk class and the mapping will be done by EF (a TalkTag table will be created in the DB).
Michael Tranchida already described the approach for adding the objects to the context.

ASP.NET Cannot get FULL list of ALL countries in the world

There are 196 countries in the world.
I'm trying to show a dropdown list that show all of them.
I see many developer suggest using CultureInfo of ASP.NET but it's missing some countries because Culture & Country are different things.
So how can I get a list of all countries for my purpose please ?. I really appreciate your help.
In ASP.NET a DropDown
<asp:DropDownList ID="selCountries" runat="server"></asp:DropDownList>
is equivalent to
<select id="selCountries"></select>
Alternatively, you could use a Web service to fill a select tag with countries through JavaScript XMLHttpRequest object.
Example: https://restcountries.eu/
Something like this:
(function() {
var newXHR;
function sendXHR(options) { // Helper function.
newXHR = new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP");
if (options.sendJSON === true) {
options.contentType = "application/json; charset=utf-8";
options.data = JSON.stringify(options.data);
} else {
options.contentType = "application/x-www-form-urlencoded";
}
newXHR.open(options.type, options.url, options.async || true);
newXHR.setRequestHeader("Content-Type", options.contentType);
newXHR.send((options.type == "POST") ? options.data : null);
newXHR.onreadystatechange = options.callback;
return newXHR;
}
sendXHR({
type: "GET",
url: "https://restcountries.eu/rest/v1/all",
callback: function() {
if (newXHR.readyState === 4 && newXHR.status === 200) {
var data = JSON.parse(newXHR.response);
var selCountries = document.getElementById("selCountries"); // Get the select tag.
// You can get the selected country.
selCountries.onchange = function() {
alert(this.value);
};
var option;
for (var i = 0; i < data.length; i++) { // For every country make an option tag.
option = document.createElement("option");
selCountries.options.add(option, 0);
selCountries.options[0].value = data[i].name; // Country name from the index «i» of the data array.
selCountries.options[0].innerText = data[i].name;
selCountries.appendChild(option); // Append the option tag to the select tag.
}
}
}
});
})();
<select id="selCountries"></select>
In ASP.NET MVC5 NET 4.5, you can bind an object to #Html.DropDownList by using ViewBag.
You need to create a model according to https://restcountries.eu/rest/v1/all json response.
Model: CountryModel.cs
using System.Collections.Generic;
namespace RestCountries.Models
{
public class Translations
{
public string de { get; set; }
public string es { get; set; }
public string fr { get; set; }
public string ja { get; set; }
public string it { get; set; }
}
public class CountryModel
{
public string name { get; set; }
public string capital { get; set; }
public List<string> altSpellings { get; set; }
public string relevance { get; set; }
public string region { get; set; }
public string subregion { get; set; }
public Translations translations { get; set; }
public int population { get; set; }
public List<object> latlng { get; set; }
public string demonym { get; set; }
public double? area { get; set; }
public double? gini { get; set; }
public List<string> timezones { get; set; }
public List<object> borders { get; set; }
public string nativeName { get; set; }
public List<string> callingCodes { get; set; }
public List<string> topLevelDomain { get; set; }
public string alpha2Code { get; set; }
public string alpha3Code { get; set; }
public List<string> currencies { get; set; }
public List<object> languages { get; set; }
}
}
Controller: DefaultController.cs
using RestCountries.Models;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web.Mvc;
namespace RestCountries.Controllers
{
public class DefaultController : Controller
{
// GET: Default
public ActionResult Index()
{
string url = "https://restcountries.eu/rest/v1/all";
// Web Request with the given url.
WebRequest request = WebRequest.Create(url);
request.Credentials = CredentialCache.DefaultCredentials;
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string jsonResponse = null;
// Store the json response into jsonResponse variable.
jsonResponse = reader.ReadLine();
if (jsonResponse != null)
{
// Deserialize the jsonRespose object to the CountryModel. You're getting a JSON array [].
List<CountryModel> countryModel = Newtonsoft.Json.JsonConvert.DeserializeObject<List<CountryModel>>(jsonResponse);
// Set the List Item with the countries.
IEnumerable<SelectListItem> countries = countryModel.Select(x => new SelectListItem() { Value = x.name, Text = x.name });
// Create a ViewBag property with the final content.
ViewBag.Countries = countries;
}
return View();
}
}
}
View: Index.cshtml
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Html.DropDownList("Countries")
Result:

Resources