I'm trying to insert data into a SQL Server database using a console application. Data to be inserted is in a json object (it is the web api post method request body). Can anyone please tell me how to use json object to insert into a SQL Server database?
Here is the code:
namespace CreateEntityConsole
{
class Entity
{
string domain = "DESKTOP-I4VK2LV";
string userName = "AP-502";
string password = "pass";
string appID = "bbb";
string locale = "en-US";
string contenttype = string.Empty;
// Create ENTITY
public string CreateEntity()
{
string URI = "http://localhost:13490/agilepointserver/extension/createentity";
string JsonRequestData = "{\"EntityName\":[\"AccountContact\":[\"PropertiesJSON\":[\"AName\": \"chaitratest2\",\"region\": \"India\"]]]}";
HttpOperations ops = new HttpOperations(domain, this.userName, password, appID, locale);
// HttpOperations ops = new HttpOperations(this.userName, password, appID, locale);
return ops.InsertEntity(URI, JsonRequestData);
}
public void InsertIntoDB(string JsonRequestData)
{
using (SqlConnection sqlCon = new SqlConnection())
{
sqlCon.ConnectionString = "server=DESKTOP-I4VK2LV;Integrated Security=True;database=Entity";
sqlCon.Open();
}
}
}
}
Use Entity framework to save json objects instead of using sqlConnection
Your can than save this to a new Ef Dbcontext(), in your case consider to deserializing json string into simple poco objects take a look at Deserializing JSON data to C# using JSON.NET
namespace CreateEntityConsole
{
public class Entity
{
private DbContext context;
public Entity()
{
context = new DbContext();
}
public void InsertIntoDB(Object JsonRequestData)
{
context.Entity.Add(JsonRequestData);
context.SaveChanges();
}
//Other CRUD stuff
}
}
Note that code first method is used, separating your the model from data access code is good practice
public class Entity {
string domain = "DESKTOP-I4VK2LV";
string userName = "AP-502";
string password = "pass";
}
public class DataAccessLayer{
DbContext context=new DbContext();
public void InsertIntoDB(Object JsonRequestData)
{
//Save json object to Entity poco
context.Entity.Add(JsonRequestData);
context.SaveChanges();
}
//Other CRUD stuff
}
Related
I developed and API that uses a helper class to get the database context for each endpoint function. Now I'm trying to write unit tests for each endpoint and I want to use an In-memory db in my unit test project.
The issue I'm running into is that in order to call the API functions I had to add a constructor to my API controller class. This would allow me to pass the dbContext of the in-memory db to the controller function for it to use. However, since the adding of the constuctor I got the following error when attempting to hit the endpoint:
"exceptionMessage": "Unable to resolve service for type 'AppointmentAPI.Appt_Models.ApptSystemContext' while attempting to activate 'AppointmentAPI.Controllers.apptController'."
UPDATE
controller.cs
public class apptController : Controller
{
private readonly ApptSystemContext _context;
public apptController(ApptSystemContext dbContext)
{
_context = dbContext;
}
#region assingAppt
/*
* assignAppt()
*
* Assigns newly created appointment to slot
* based on slotId
*
*/
[Authorize]
[HttpPost]
[Route("/appt/assignAppt")]
public string assignAppt([FromBody] dynamic apptData)
{
int id = apptData.SlotId;
string json = apptData.ApptJson;
DateTime timeStamp = DateTime.Now;
using (_context)
{
var slot = _context.AppointmentSlots.Single(s => s.SlotId == id);
// make sure there isn't already an appointment booked in appt slot
if (slot.Timestamp == null)
{
slot.ApptJson = json;
slot.Timestamp = timeStamp;
_context.SaveChanges();
return "Task Executed\n";
}
else
{
return "There is already an appointment booked for this slot.\n" +
"If this slot needs changing try updating it instead of assigning it.";
}
}
}
}
UnitTest.cs
using System;
using Xunit;
using AppointmentAPI.Controllers;
using AppointmentAPI.Appt_Models;
using Microsoft.EntityFrameworkCore;
namespace XUnitTest
{
public abstract class UnitTest1
{
protected UnitTest1(DbContextOptions<ApptSystemContext> contextOptions)
{
ContextOptions = contextOptions;
SeedInMemoryDB();
}
protected DbContextOptions<ApptSystemContext> ContextOptions { get; }
private void SeedInMemoryDB()
{
using(var context = new ApptSystemContext(ContextOptions))
{
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var seventh = new AppointmentSlots
{
SlotId = 7,
Date = Convert.ToDateTime("2020-05-19 00:00:00.000"),
Time = TimeSpan.Parse("08:45:00.0000000"),
ApptJson = null,
Timestamp = null
};
context.AppointmentSlots.Add(seventh);
context.SaveChanges();
}
}
[Fact]
public void Test1()
{
DbContextOptions<ApptSystemContext> options;
var builder = new DbContextOptionsBuilder<ApptSystemContext>();
builder.UseInMemoryDatabase();
options = builder.Options;
var context = new ApptSystemContext(options);
var controller = new apptController(context);
// Arrange
var request = new AppointmentAPI.Appt_Models.AppointmentSlots
{
SlotId = 7,
ApptJson = "{'fname':'Emily','lname':'Carlton','age':62,'caseWorker':'Brenda', 'appStatus':'unfinished'}",
Timestamp = Convert.ToDateTime("2020-06-25 09:34:00.000")
};
string expectedResult = "Task Executed\n";
// Act
var response = controller.assignAppt(request);
Assert.Equal(response, expectedResult);
}
}
}
InMemoryClass.cs
using System;
using System.Data.Common;
using Microsoft.EntityFrameworkCore;
using AppointmentAPI.Appt_Models;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore.Infrastructure;
namespace XUnitTest
{
public class InMemoryClass1 : UnitTest1, IDisposable
{
private readonly DbConnection _connection;
public InMemoryClass1()
:base(
new DbContextOptionsBuilder<ApptSystemContext>()
.UseSqlite(CreateInMemoryDB())
.Options
)
{
_connection = RelationalOptionsExtension.Extract(ContextOptions).Connection;
}
private static DbConnection CreateInMemoryDB()
{
var connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
return connection;
}
public void Dispose() => _connection.Dispose();
}
}
The exception suggests that you haven't registered your DBContext in your Startup.cs (as mentioned above). I'd also suggest that you change the name of your private readonly property to something other than DbContext (which is the class name and can get confusing)
Use something like this:
private readonly ApptSystemContext _context;
Besides that, your approach should be changed.
First, you will set the connection string when you register the DBContext. Just let dependency injection take care of that for you. Your controller should look like this:
public apptController(ApptSystemContext dbContext)
{
_context = dbContext;
}
The dbContext won't be null if you register it in Startup.
Next, unit testing is a tricky concept, but once you write your Unit test, you'll start to understand a little better.
You've said that you want to use the SQL In Memory db for unit testing, which is a good approach (be aware that there are limitations to SQL In Mem like no FK constraints). Next, I assume you want to test your Controller, so, since you MUST pass in a DBContext in order to instantiate your Controller, you can create a new DBContext instance that is configured to use the In Memory Database.
For example
public void ApptControllerTest()
{
//create new dbcontext
DbContextOptions<ApptSystemContext> options;
var builder = new DbContextOptionsBuilder<ApptSystemContext>();
builder.UseInMemoryDatabase();
options = builder.Options;
var context = new ApptSystemContext(options);
//instantiate your controller
var controller = new appController(context);
//call your method that you want to test
var retVal = controller.assignAppt(args go here);
}
Change the body of the method to this:
public string assignAppt([FromBody] dynamic apptData)
{
int id = apptData.SlotId;
string json = apptData.ApptJson;
DateTime timeStamp = DateTime.Now;
using (_context)
{
var slot = _context.AppointmentSlots.Single(s => s.SlotId == id);
// make sure there isn't already an appointment booked in appt slot
if (slot.Timestamp == null)
{
slot.ApptJson = json;
slot.Timestamp = timeStamp;
_context.SaveChanges();
return "Task Executed\n";
}
else
{
return "There is already an appointment booked for this slot.\n" +
"If this slot needs changing try updating it instead of assigning it.";
}
}
}
Another suggestion, don't use a dynamic object as the body of a request unless you are absolutely forced to do so. Using a dynamic object allows for anything to be passed in and you lose the ability to determine if a request is acceptible or not.
I created a bot application by using bot framework in visual c# and I published it in Azure. My database also in Azure. I give the CompanyId, TenantId, SiteId and Bandid via bot, then should reply as CompanyName and Address from database. It written in TestData.cs class.
I attached my TestAPIController also and I want to get the data from database into bot application. How to code my RootDialog.cs ?
public class TestAPIController : ApiController
{
[HttpGet]
public IHttpActionResult Get(string TenantId, string CompanyId, string SiteId, string BandId)
{
TestData TestData = new TestData();
var TestBusiness = TestData.Select(TenantId, CompanyId, SiteId, BandId);
return Ok(TestBusiness);
}
}
public class TestData :DBConnection
{
public List<TestBusiness> Select(string TenantId, string CompanyId, string SiteId, string BandId)
{
List<TestBusiness> list = new List<TestBusiness>();
this.StoredProcedure = "RESQBOTGetCompanywiseData";
AddParameter("TenantId", TenantId);
AddParameter("CompanyId", CompanyId);
AddParameter("SiteId", SiteId);
AddParameter("BandId", BandId);
DataTable dt = this.ExecuteSelect();
foreach (DataRow dr in dt.Select())
{
TestBusiness item = new TestBusiness();
item.CompanyName = dr["CompanyName"].ToString();
item.Address = dr["Address"].ToString();
list.Add(item);
}
return list;
}
}
you have to make use of HttpClient that allows you to call webapi and get data below is example code
using(var client = newHttpClient())
{
client.BaseAddress = newUri("http://localhost:55587/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add
(newMediaTypeWithQualityHeaderValue("application/json"));
//GET Method
HttpResponseMessage response =
await client.GetAsync("GetAllRows/1/1/1/1");
if (response.IsSuccessStatusCode)
{
}
}
you also need to set route in you web api as below , and pass all parameter when calling this method
[Route("GetAllRows/{TenantId}/{CompanyId}/{SiteId}/{BandId}")]
public IHttpActionResult Get(string TenantId, string CompanyId,
string SiteId, string BandId)
{
}
also configure you webapi for route attribute based routing
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
}
Follow this article : https://dzone.com/articles/web-api-with-httpclient-or-consume-web-api-from-co
In the RootDialog.cs, I created object that instance of TestAPIController. Then call that one and pass inputs as parameters. I show the data that are in first data of the Database.
TestAPIController Test = new TestAPIController();
returnData = Test.Get(TenantId, CompanyId, SiteId, BandId);
string companyName = returnData[0].CompanyName.ToString();
string address= returnData[0].Address.ToString();
await context.PostAsync("Company Name = "+ companyName + " and It's address is "+ address);
I'm attempting to make an existing application work without an app.config (it is required due to a very specific environment). Problem is that it's heavily relying on EntityFramework 6 to work with an SQL-Server.
I'm trying to use a code-based configuration, but I can't figure out how to provide a correct connection string through my configuration class.
I made a configuration class:
public class MyConfiguration : DbConfiguration
{
public MyConfiguration()
{
SetDefaultConnectionFactory(new MyConnectionFactory());
SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
}
}
Then provided it to my DbContext (Generated by EF automatically from bd):
[DbConfigurationType(typeof(MyConfiguration))]
public partial class TestModelEntities
{
}
With a custom connection factory:
public class MyConnectionFactory : IDbConnectionFactory
{
public DbConnection CreateConnection(string nameOrConnectionString)
{
var newConnStringBuilder = new SqlConnectionStringBuilder
{
UserID = "user",
Password = "pass",
InitialCatalog = "databaseName",
DataSource = "serverName"
};
var entityConnectionBuilder = new EntityConnectionStringBuilder
{
Provider = "System.Data.SqlClient",
ProviderConnectionString = newConnStringBuilder.ToString(),
Metadata = #"res://*/TestModel.csdl|
res://*/TestModel.ssdl|
res://*/TestModel.msl"
};
var newDbConnect = new EntityConnection(entityConnectionBuilder.ToString());
return newDbConnect;
}
}
However. When I test it, I get an UnintentionalCodeFirstException. Why? What am I missing?
You should provide connection string to your context via :base(connectionString). Create a class as below:
public class ConnectionStringBuilder
{
public static string Construct()
{
var newConnStringBuilder = new SqlConnectionStringBuilder
{
UserID = "user",
Password = "pass",
InitialCatalog = "databaseName",
DataSource = "serverName"
};
var entityConnectionBuilder = new EntityConnectionStringBuilder
{
Provider = "System.Data.SqlClient",
ProviderConnectionString = newConnStringBuilder.ToString(),
Metadata = #"res://*/TestModel.csdl|
res://*/TestModel.ssdl|
res://*/TestModel.msl"
};
return entityConnectionBuilder.ToString();
}
}
Then modify your Context constructor to look like this:
public DbContext()
: base(ConnectionStringBuilder.Construct())
{
}
It should work fine now. (source)
Currently I'm working on a C# WebApi.
I made my own TokenAuthorizationAttribute, which checks if the string in the "Authorization"-Header matches the string in a Database.
This works just fine, I can decorate controllers and methods with the attribute and it works.
However now I'm trying to write a method that uses the passed token. Of course i could read out the header again, but i don't want to do that because it needs time (and the method has to work fast). I thought of maybe saving the token to a property of the TokenAuthorizationAttribute, but how can i get the value of it in my method?
Here's the code of my Attribute:
public class TokenAuthorizationAttribute : AuthorizationFilterAttribute {
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext) {
public string Token {get; set;}
IEnumerable<string> values;
if (actionContext.Request.Headers.TryGetValues("Authorization", out values)) {
string token = values.FirstOrDefault();
string auth = String.Empty;
SqlConnection conn = SqlService.OpenConnection();
SqlCommand cmd = new SqlCommand("SELECT-Token-Statement", conn);
auth = (string)cmd.ExecuteScalar();
conn.Close();
if (!string.IsNullOrEmpty(auth)) {
Token = auth;
base.OnAuthorization(actionContext);
}
else {
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized) {
ReasonPhrase = "Wrong Token"
};
}
}
else{
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized){
ReasonPhrase = "Missing Token"
and my method looks something like that:
[TokenAuthorization]
public static void MyMethod(string value) {
string token = "How do i get the Token?";
}
I have generated entity model from AdventureWorks database; now I want to delete the connection string in app.config and set it at runtime. In the Model1.Context.cs file I have chnaged the constructor to
public AdventureWorksEntities(string str)
: base("name=AdventureWorksEntities")
{
this.Database.Connection.ConnectionString = str;
}
and in the program.cs file
EntityConnectionStringBuilder ecsb = new EntityConnectionStringBuilder();
ecsb.Metadata = #"res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl";
ecsb.Provider = #"System.Data.SqlClient";
ecsb.ProviderConnectionString =
#"data source=.\sqlexpress;initial catalog=AdventureWorks;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework";
using (var ent = new AdventureWorksEntities(ecsb.ConnectionString))
{
Console.WriteLine(ent.Database.Connection.ConnectionString);
var add = ent.Addresses;
foreach (var ad in add)
{
Console.WriteLine(ad.City);
}
}
Console.ReadKey();
Now it says metadata keyword not found. How to set connectionstring for entityframework at runtime?
This is an example using standard .aspx login information to set the UserID and Password information in the connection string. No connection string settings are stored in the web.config or app.config file.
Modify the Model.Designer.cs page as follows:
public partial class Entities : ObjectContext
{
#region Constructors
public static string getConStrSQL(string UID,string PWD)
{
string connectionString = new System.Data.EntityClient.EntityConnectionStringBuilder
{
Metadata = "res://*",
Provider = "System.Data.SqlClient",
ProviderConnectionString = new System.Data.SqlClient.SqlConnectionStringBuilder
{
InitialCatalog = "your_database_name",
DataSource = "your_server",
IntegratedSecurity = false,
UserID = UID,
Password = PWD,
}.ConnectionString
}.ConnectionString;
return connectionString;
}
/// <summary>
/// Initialize a new Entities object.
/// </summary>
public Entities(string UID,string PWD)
: base(getConStrSQL(UID,PWD), "Entities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
......
Then in your code behind page:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Mvc;
using System.Web.Security;
public partial class views_html_form : System.Web.UI.Page
{
public void Page_Load()
{
if (currentUser() == null)
{
HttpContext.Current.Response.Redirect("~/login.aspx");
}
}
public static MembershipUser currentUser()
{
MembershipUser currentUser = Membership.GetUser();
return currentUser;
}
public static string UID()
{
string UID = currentUser().UserName;
return UID;
}
public static string PWD()
{
string PWD = currentUser().GetPassword();
return PWD;
}
public static void SelectRecord()
{
YourModel.Entities db = new YourModel.Entities(UID(), PWD());
var query = from rows in db.Table_Name orderby rows.ID select rows;
.....
That's it. No messing around with .config files. Alternatively you could send a database name, for example, as a parameter in the same way.
I'd go with something like:
public AdventureWorksEntities(string server, string databaseName, string user, string password)
:base(new System.Data.EntityClient.EntityConnectionStringBuilder
{
Metadata = "res://*",
Provider = "System.Data.SqlClient",
ProviderConnectionString = new System.Data.SqlClient.SqlConnectionStringBuilder
{
InitialCatalog = databaseName,
DataSource = server,
IntegratedSecurity = false,
UserID = user,
Password = password,
}.ConnectionString
}.ConnectionString)
{
}