There is the complete code of the test.
When posting JSON data to the API, the instance person is null.
Can any one tell me why
Model
public class Diploma
{
public int PeronId { get; set; }
public string Tile { get; set; }
public string Organism { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public string Function { get; set; }
public List<Diploma> Diplomas { get; set; }
public Person()
{
Diplomas = new List<Diploma>();
}
}
Controller
public class PersonnesController : ApiController
{
private const string cs = "Data Source=.;Initial Catalog=test;Integrated Security=True";
// POST : Person
[HttpPost]
public int Post([FromBody] Person person)
{
bool res = false;
int id;
SqlCommand cmd = new SqlCommand();
using (SqlConnection connection = new SqlConnection(cs))
{
cmd = new SqlCommand("insert dbo.personnes (Name, Function) output INSERTED.ID values (#name, #function)", connection);
cmd.Parameters.AddWithValue("#nam", person.Name);
cmd.Parameters.AddWithValue("#function", person.Function);
connection.Open();
id = (int)cmd.ExecuteScalar();
foreach (Diploma diploma in person.Diplomas)
{
cmd = new SqlCommand("insert diplomes values(#id, #title, #organism)", connection);
cmd.Parameters.AddWithValue("#id", id);
cmd.Parameters.AddWithValue("#title", diploma.Tile);
cmd.Parameters.AddWithValue("#organism", diploma.Organism);
cmd.ExecuteNonQuery();
}
return id;
}
}
}
I'm testing with RESTClient for Firefox,
In header section:
Content-type : application/x-www-form-urlencoded
The data is being sent using the wrong Content-Type.
It was indicated that data was sent using Content-type : application/x-www-form-urlencoded
while the shown data is JSON
{ "Name": "my name", "Function": "my function", "diplomas": [{ "title": "diploma 1", "organism": "university 1" }, { "title": "diploma 2", "organism": "university 2" }] }
which would use Content-type : application/json content type
The model binder was unable to parse the content using the provided content type, so it default the model to null.
Related
I am trying to connect my ASP.NET Core 6 application to SQL Server, but I get an error on the connection string. Does anyone have experience with .NET 6 that could help?
This is my code in my class (book.cs). I get the ERROR where I commented in the code. And yes I have the right string in the app.json file
public class Book
{
public int BookId { get; set; }
public int Pagecount { get; set; }
public string Title { get; set; }
public string TypeName { get; set; }
public string AutherFirstName { get; set; }
public string AutherLastName { get; set; }
public List<Book> GetBooks(string connectionString)
{
List<Book> bookList = new List<Book>();
SqlConnection con = new SqlConnection (connectionString);
string selectSQL = "select BookId, Title, Isbn, PublisherName, AuthorName, CategoryName from GetBookData";
con.Open(); // Here i get my error
SqlCommand cmd = new SqlCommand(selectSQL, con);
SqlDataReader dr = cmd.ExecuteReader();
if (dr != null)
{
while (dr.Read())
{
Book book = new Book();
book.BookId = Convert.ToInt32(dr["BookId"]);
book.Pagecount = Convert.ToInt32(dr["pagecount"]);
book.Title = dr["Title"].ToString();
book.TypeName = dr["TypeName"].ToString();
book.AutherLastName = dr["AutherLastName"].ToString();
book.AutherFirstName = dr["AutherFirstName"].ToString();
}
}
return bookList;
}
I would say configurations in .NET are annoying stuff but, let's skip that ;)
The usage of options is done after some DI logic. So basically, your problem probably is in how you are trying to get the value from appsettings.{ENV}.json.
You haven't attached this part of the code but when you are calling your method from the Book.cs class, you should do something like that:
new Book().GetBooks(_configuration.GetConnectionString("connStrKey"));
BTW this is an anti-pattern and I strongly recommend you start using the Options Pattern to inject options and settings into your code.
https://learn.microsoft.com/en-us/dotnet/core/extensions/options
So, your code should be changed to something like that:
public class ConnectionStrings
{
public ConnectionStrings()
{
ConnectionString = string.Empty;
}
public string ConnectionString { get; set; }
}
public class BooksRepository
{
private readonly ConnectionStrings connectionStringsOptions;
public BooksRepository(IOptions<ConnectionStrings> connectionOptions)
{
connectionStringsOptions = connectionOptions.Value;
}
public List<Book> GetBooks()
{
List<Book> bookList = new List<Book>();
SqlConnection con = new SqlConnection(connectionStringsOptions.ConnectionString);
string selectSQL = "select BookId, Title, Isbn, PublisherName, AuthorName, CategoryName from GetBookData";
con.Open();
SqlCommand cmd = new SqlCommand(selectSQL, con);
SqlDataReader dr = cmd.ExecuteReader();
if (dr != null)
{
while (dr.Read())
{
bookList.Add(new Book
{
BookId = Convert.ToInt32(dr["BookId"]),
Pagecount = Convert.ToInt32(dr["pagecount"]),
Title = dr["Title"].ToString(),
TypeName = dr["TypeName"].ToString(),
AutherLastName = dr["AutherLastName"].ToString(),
AutherFirstName = dr["AutherFirstName"].ToString()
});
}
}
return bookList;
}
}
public class Book
{
public int BookId { get; set; }
public int Pagecount { get; set; }
public string Title { get; set; }
public string TypeName { get; set; }
public string AutherFirstName { get; set; }
public string AutherLastName { get; set; }
}
Since you are using .net 6, update your program.cs class to add the connection strings as DI Options adding the following line before the "var app = builder.Build();" statement.
builder.Services.Configure<ConnectionStrings>(builder.Configuration.GetSection("ConnectionStrings"));
Example of a appsettings.json section
{
"ConnectionStrings": {
"ConnectionString": "localhost:1433"
}
}
I eventually came to the answer.
Had to change the query in SQL and put part of the code into a try/catch block and it worked.
string ConnectionString = "Data Source=localhost\\SQLEXPRESS;Initial Catalog=RFID_Library;Integrated Security=True; TrustServerCertificate=True";
string errormsg = null;
List<Book> bookList = new List<Book>();
try
{
SqlConnection con = new SqlConnection(ConnectionString);
string selectSQL = "select BookId, Title, pagecount, AutherFirstName, AutherLastName, TypeName from GetBookData";
con.Open();
SqlCommand cmd = new SqlCommand(selectSQL, con);
SqlDataReader dr = cmd.ExecuteReader();
if (dr != null)
{
while (dr.Read())
{
Book book = new Book();
book.BookId = Convert.ToInt32(dr["BookId"]);
book.Pagecount = Convert.ToInt32(dr["pagecount"]);
book.Title = dr["Title"].ToString();
book.TypeName = dr["TypeName"].ToString();
book.AutherLastName = dr["AutherLastName"].ToString();
book.AutherFirstName = dr["AutherFirstName"].ToString();
bookList.Add(book);
}
}
return bookList;
}
catch (Exception)
{
throw;
}
Im looping through all the results from the SQL query in a .Net Core project. here is Model
public class Mymessagesinfo
{
public int MyMessagesCount { get; set; }
public List<int> MessagesIDs { get; set; }
public List<int> MessagesSendersid { get; set; }
public List<string> MessagesSenders { get; set; }
public List<string> MessagesTitles { get; set; }
public List<string> MessagesInformation { get; set; }
public List<string> MessagesStatus { get; set; }
}
I loop through the users messages in my controller then i pass that model to the view
sqlcon.Open();
int? userid = HttpContext.Session.GetInt32("UserID");
SqlCommand sqlcom = new SqlCommand("select * from messages where Messagereceiver=" +userid , sqlcon);
SqlDataReader reader = sqlcom.ExecuteReader();
if(reader.HasRows)
{
int index = 0;
while(reader.Read())
{
string s;
s = reader[0].ToString();
Mymessages.MessagesIDs.Add(int.Parse(s));
Mymessages.MessagesSendersid.Add(int.Parse(reader[1].ToString()));
Mymessages.MessagesTitles.Add(reader[3].ToString());
Mymessages.MessagesInformation.Add(reader[4].ToString());
Mymessages.MessagesStatus.Add(reader[5].ToString());
index++;
}
Mymessages.MyMessagesCount = index;
}
the very first line Mymessages.MessagesIDs.Add(int.Parse(s)); it throws an exception saying System.NullReferenceException: 'Object reference not set to an instance of an object
i wanted to make sure that reader was holding the results so i added int s and checked on it and it was holding the value it was supposed to.
whats going wrong here? is this how we are supposed to pass list-like data to the view?
You need to initlize MessagesIDs in entity Mymessages, like this:
var Mymessages = new Mymessagesinfo()
{
MessagesIDs = new List<int>()
};
Mymessages.MessagesIDs.Add(id);
Or just define the class like this,
public class Mymessagesinfo
{
public int MyMessagesCount { get; set; }
public List<int> MessagesIDs { get; set; } = new List<int>();
public List<int> MessagesSendersid { get; set; } = new List<int>();
public List<string> MessagesSenders { get; set; } = new List<string>();
public List<string> MessagesTitles { get; set; } = new List<string>();
public List<string> MessagesInformation { get; set; } = new List<string>();
public List<string> MessagesStatus { get; set; } = new List<string>();
}
Here is how I would restructure what you have to make it work.
First, your model class:
public class Mymessagesinfo
{
public List<MessageInfo> Messages { get; set; } = new List<MessageInfo>();
}
public class MessageInfo
{
public int ID { get; set; }
public int Senderid { get; set; }
public string Sender { get; set; }
public string Title { get; set; }
public string Information { get; set; }
public string Status { get; set; }
}
With this approach you have a list of message objects, instead of a bunch of lists containing property data.
Here is how I would suggest you load it from SQL Server:
var data = new Mymessagesinfo();
int? userid = HttpContext.Session.GetInt32("UserID");
var messagesTable = new System.Data.DataTable("messages");
using (var sqlcom = sqlcon.CreateCommand())
{
sqlcom.CommandText = $"select * from messages where Messagereceiver='{userid}'";
using (var adapter = new SqlDataAdapter(sqcom))
{
adapter.Fill(messagesTable);
}
}
// we are now done with SQL and have the data in memory...
foreach(DataRow row in messagesTable.Rows)
{
data.Messages.Add( new MessageInfo {
ID = row.Field<int>(0),
Senderid = row.Field<int>(1),
Sender = row.Field<string>(2),
Title = row.Field<string>(3),
Information = row.Field<string>(4),
Status = row.Field<string>(5),
});
}
return View(data);
This is a lot cleaner and by using a DataAdapter and DataTable you minimize the amount of time that the connection to the database is connected.
Here is how you would use this model in an MVC View:
#Model Mymessagesinfo
<div>
<!-- This is where you can display the properties of the message. //-->
<ul>
#foreach(var message in Model.Messages)
{
<li> #message.Title - #message.Id </li>
}
<ul>
<div>
I am building a web api with net core, I need to use the post method to save the information of a json file, the drawback is that the json file has an array and I do not know how to send the information to the stored procedure in sql so that it save the information the json file is this
"buyer": { //
"firstName": "fabio",
"lastName": "gomez",
"documentType": 0, // Puede ser 0: DNI, 1: Pasaporte o 2: Carnet de Extranjeria
"documentNumber": "01234567", // Permitir letras para pasaportes extranjeros
"phoneNumber": "51912345678",
"email": "hnos#gmail.com"
},
"passengers": [{ // En el primer pasajero, pueden repetirse los datos del comprador
"seat": 1,
"firstName": "pedro",
"lastName": "peres", // Considerar nueva campo
"secondLastName": "martinez",
"documentType": 0, // Puede ser 0: DNI, 1: Pasaporte o 2: Carnet de Extranjeria
"documentNumber": "15588",
"age": 42,
"gender": 0, // Puede ser 0: Masculino, 1: Femenino
},
{
"seat": 2,
"firstName": "Adriana",
"lastName": "gomez",
"secondLastName": "lopez",
"documentType": 1, // Puede ser 0: DNI, 1: Pasaporte o 2: Carnet de Extranjeria
"documentNumber": "XY01234567",
"age": 40,
"gender": 1, // Puede ser 0: Masculino, 1: Femenino
}
],
This json must enter the system via post, which I use the following driver
[HttpPost]
public async Task<IActionResult> Post([FromBody] List<string> valores)
{
await _repository.Insert(valores);
return Ok();
}
try doing something with ado.net but it doesn't work
public async Task Insert(List<string> parametros)
{
using (SqlConnection sql = new SqlConnection(_connectionString))
{
using (SqlCommand cmd = new SqlCommand("sp_insertarpasajero", sql))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
//cmd.Parameters.Add(new SqlParameter("#Id", parametros));
await sql.OpenAsync();
await cmd.ExecuteNonQueryAsync();
return;
}
}
}
I do not know how to pass the information from the controller that receives the post to an object or datatable and then use it in a stored procedure I appreciate your collaboration
For you json file , you should create a model object to accept the json data .The following is my working demo , you could refer to and make the modification on your project:
Model
public class Buyer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int DocumentType { get; set; }
public string DocumentNumber { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
}
public class Passenger
{
public int Id { get; set; }
public int Seat { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string SecondLastName { get; set; }
public int DocumentType { get; set; }
public string DocumentNumber { get; set; }
public string Age { get; set; }
public int Gender { get; set; }
}
public class OrderInfo
{
public Buyer Buyer { get; set; }
public List<Passenger> Passengers { get; set; }
}
Stored procedure , use OPENJSON (Transact-SQL)
CREATE PROCEDURE [dbo].[sp_insertpassenger]
#json NVARCHAR(max)
AS
INSERT INTO Passenger(
Seat,FirstName,LastName,SecondLastName,
DocumentType,DocumentNumber,Age,Gender)
Select *
FROM OPENJSON(#json ,'$.Passengers')
WITH(
Seat int '$.Seat',
FirstName nvarchar(50) '$.FirstName',
LastName nvarchar(50) '$.LastName',
SecondLastName nvarchar(50) '$.SecondLastName',
DocumentType int '$.DocumentType',
DocumentNumber nvarchar(50) '$.DocumentNumber',
Age int '$.Age',
Gender int '$.Gender' );
RETURN 0
Controller and repository method
[HttpPost]
public async Task<IActionResult> Post([FromBody] OrderInfo values)
{
await _repository.Insert(values);
return Ok();
}
public async Task Insert(OrderInfo parameter)
{
using (SqlConnection sql = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand("sp_insertpassenger", sql))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
var json = JsonConvert.SerializeObject(parameter);
cmd.Parameters.Add(new SqlParameter("#json", json));
await sql.OpenAsync();
await cmd.ExecuteNonQueryAsync();
return;
}
}
}
Result
I have a simple ASP.NET Class with 4 properties. What I'd like to to is package this class into a JSON string and add a "data" parent at the top level. What's the best way to add in the "data" element at the top level?
using Newtonsoft.Json;
[DataContract]
public class Task
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "notes")]
public string Notes { get; set; }
}
static void Main(string[] args)
{
var task = new Task();
task.Name = "Test Task";
task.Notes = "Test task created by ASP.NET";
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://example.com/api");
HttpResponseMessage response = client.PostAsJsonAsync<Task>("tasks", task).Result;
response.EnsureSuccessStatusCode();
string responseBody = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(responseBody);
Console.ReadLine();
}
The Json I am getting back from this code is the following:
{
"name": "Test Task",
"notes": "Test task created by ASP.NET",
}
What I'd like is the following:
{
"data": {
{
"name": "Test Task",
"notes": "Test task created by ASP.NET",
}
}
You could create a simple dictionary:
public class Task
{
public Task
{
Data = new Dictionary<string,string>();
}
[DataMember(Name = "data")]
public Dictionary<string,string> Data { get; private set; }
}
Populate like:
Task t =new Task();
t.Data.Add("name","test task");
t.Data.Add("notes","teet");
Yes you could create another class and embed it like this also:
public class Data
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "notes")]
public string Notes { get; set; }
}
public class Task
{
public Task
{
Data = new Data();
}
[DataMember(Name = "data")]
public Data Data { get; private set; }
}
You could use generics for an abstracted Data
public class Task<T> where T: class , new()
{
public Task
{
Data = new T();
}
[DataMember(Name = "data")]
public T Data { get; private set; }
}
If your service provider is wcf (i guess it is wcf), change the BodyStyle of the method to WebMessageBodyStyle.Bare as mentioned below.
BodyStyle = WebMessageBodyStyle.Bare
it will not wrap the result.
I want to get the book name which is in the first column of gridview. I used Template field and added a link button in it. Book name is retrieved from database, thus dynamically wriiten. I want open the selected book in pdf in another page.
public class Book
{
public string Bookn{get;set;}
public string Auth { get; set; }
public string Category { get; set; }
public string Edi { get; set; }
public string Yopub { get; set; }
public string Avai { get; set; }
public string img { get; set; }
}
public class GetData
{
public static List<Book> Getallrecord(string author)
{
List<Book> ob1 = new List<Book>();
SqlConnection con;
SqlCommand com;
string cs = ConfigurationManager.ConnectionStrings["SDL_DBConnectionString"].ConnectionString;
using (con = new SqlConnection(cs))
{
com = new SqlCommand("searchByAuthor3", con);
com.CommandType = CommandType.StoredProcedure;
com.Parameters.AddWithValue("#SAuthor", author + "%");
con.Open();
SqlDataReader rd = com.ExecuteReader();
while (rd.Read())
{
Book bo = new Book();
bo.Bookn = rd["BookName"].ToString();
bo.Auth = rd["Author"].ToString();
bo.Category = rd["Category"].ToString();
bo.Yopub = rd["Yopublication"].ToString();
bo.Edi = rd["Edition"].ToString();
bo.Avai = rd["Available"].ToString();
bo.img = rd["Images"].ToString();
ob1.Add(bo);
}
}
return ob1;
}
}
protected void SAButton_Click(object sender, EventArgs e)
{
string author = TAuthor.Text;
if (Session["ClientLogin"] != null)
{
SAGridView.DataSource=GetData.Getallrecord(author);
SAGridView.DataBind();
}
else
{
Server.Transfer("Login.aspx");
}
}
You can add a hyperlink field in your gridview and redirect to your other page like
<asp:HyperLinkField DataNavigateUrlFields="Bookn"
DataNavigateUrlFormatString="View_Book.aspx?BookNo={0}" Text="View Book" />