Trying to simply add a variable value to database - asp.net-core

New to asp.net core.I have a database (let's call in database123), with table Student. Student has 4 Columns, StudentId, StudentNameName, StudentGender and CreatedUtc.
No probs adding data via razor page to database. But I want the CreatedUtc value to be inserted into the database, not via the view, but via the controller (it is the date the record was created and should come from DateTime.Now.ToString or something similar.
I am having trouble figuring out where and how to code this into the Create.cshtml.cs controller. I assume it needs to be entered into the public async Task OnPostAsync().
Currently I have this
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
MessageVar += $" Server time { DateTime.Now.ToString() }"; // Get Date and Time
_context.Student.Add(Student);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
In the CreateModel area above, I have this:-
public string MessageVar { get; private set; } = "Local Server Time: ";
Any help would be greatly appreciated. I know it is probably really simple, but just having trouble finding it.
Thanks in advance,

Before saving your student, set the time.
student.createdutc = DateTime.UtcNow;

Related

The best way to save the String Variable after being redirected Page in ASP.NET CORE

How can I save the form values as a string after the page is redirected?
I use a static variable, if the number of users on the site increases for example 20000, will the site have problems?
Which method is better?
Using a static variable?
session?
Cookies?
ViewBag?
View State?
sql server database?
Actually, There is no the best method, Only the most suitable method. The methods you list above all have their own most suitable use cases.
From your comment, I think you may wanna redirect to another page with a string parameter, So you can try to use :
return RedirectToAction("actionName","controllerName",new { Name="xxx"});
It will send a get request: acontrollerName/actionName?Name=xxx.
Or, if you wanna save that string value for a long time, You can also try to use Session or Database. But one thing you need to consider is that you need to set the session time out according to the actual situation of your project.
==========================edited===========================
I think you can use Session to achieve it.
public class TestModel
{
public int ID { get; set; }
public string Name { get; set; }
}
public async Task<IActionResult> OnPostSelectMenu(int selectedid)
{
TestModel selected = await _db.Table.FindAsync(selectedid);
//set session
HttpContext.Session.SetString("Key", JsonConvert.SerializeObject(selected));
return RedirectToPage("MyPage");
}
public async Task<IActionResult> OnGetAsync()
{
//......
//get session
Input = JsonConvert.DeserializeObject<TestModel>(HttpContext.Session.GetString("Key"));
return Page();
}

NHiberate session.Get() gets the cached entity. How to get the latest entity from the DB?

I'm using the CQRS pattern to get the data from the DB using NHibernate.
Here is the CommittingTransactionCommandHandler which calls the UpdateProductHandler
class CommittingTransactionCommandHandler
{
private readonly ISession session;
private readonly ICommandHandler<TCommand> _inner; //Generic Command Handlers
public CommittingTransactionCommandHandler(ISession session)
{
this.session = session;
}
public async Task Execute(TCommand command)
{
using (var txn = session.BeginTransaction(IsolationLevel.Unspecified))
{
try
{
await _inner.Update(command); // This calls the UpdateProducthandler's Update method
txn.Commit();
}
catch (Exception ex)
{
throw;
}
}
}
}
Here is the Command Handler for the Update.
class UpdateProductHandler : ICommand
{
private readonly ISession session;
public UpdateProductHandler(ISession session)
{
this.session = session;
}
public async Task Update(int id, ProductIdentity productIdentity)
{
var product = session.Get(id);
product.Update(productIdentity);
}
}
Here is the Query Handler for the Get
class GetProductHandler
{
private readonly ISession session;
public GetProductHandler(ISession session)
{
this.session = session;
}
public async Task<Product> Get(int id)
{
var product = session.Get(id);
if (product == null)
throw new Exception("Entity not found");
return Task.FromResult(product);
}
}
Here is the code for the Product entity
class Product
{
public virtual int Id { get; protected set; }
public virtual string Name { get; protected set; }
public virtual string Description { get; protected set; }
public virtual int? Version { get; protected set; }
public virtual void Update(ProductIdentity productIdentity)
{
Name = productIdentity.Name;
Description = productIdentity.Description;
}
}
The flow is
CommittingTransactionCommandHandler is a generic command handler. This is called from the API, which internally invokes the UpdateProductHandler. The transaction is opened in this and committed here.
The scenario is that
I get a Product from the DB using the GetProductHandler. (In this case, the version number of the Product is 10.)
I'm updating the Product using the UpdateProductHandler and commits the session which is under the transaction. (Here version number of the Product is 11)
Immediately after the Update Product, I query the same Product using the GetProductHandler and loads it in the Edit mode in the UI. (But the Product fetched using the GetProductHandler has a version number 10 and not 11.)
Here is the issue, instead of getting the latest update from the DB, the above GetProductHandler, gets the previous state of the object.(Found using the version number)
Now, if I try to update the Product, I get a Stale Object State Exception since the version number is 10 which is not the latest version of the Product.
I've tried with session.Refresh(product) but all in vain as it affects the other transactions.
How can I resolve this?
As Ayende explains, Get will NOT always hit the database. It will only hit the database if entity not found in first level cache.
You have not explained how you are updating the entity; what is inside product.Update method. If you are updating using API that does not update underlying first level cache (SQL/HQL/Linq), then the problem you stated in question is obvious. In that case,
You load entity in session cache using Get (Version 10). This hits the database.
Then, you call Update (database hit) which will not update the first level cache (Version changed to 11 in database; NOT in cache).
Then you call Get again. NHibernate looks if entity is already loaded in session cache. Yes; it is (Version 10). It just returns it. No database hit.
Solution 1:
Not sure why that Update method is needed. You can directly update the entity like below:
public async Task Update(int id, ProductIdentity productIdentity)
{
var product = session.Get(id);
product.Version = 11;
//Update other properties here
...
...
//That's it. You are already calling `Flush` somewhere somehow
}
Solution 2:
As Ayende NOT recommended (and I am not recommending either), don't use Get and write a query that will hit the database. Use Linq/HQL/SQL API instead.
select customer from s.Linq<Customer>()
where customer.Id = customerId
select customer
).FirstOrDefault();
Every time that I see something like that, I wince a little inside. The reason for that is quite simple. This is doing a query by primary key. The key word here is a query.
This means that we have to hit the database in order to get a result for this query. Unless you are using the query cache (which by default you won’t), this force a query on the database, bypassing both the first level identity map and the second level cache.
Get and Load are here for a reason, they provide a way to get an entity by primary key. That is important for several aspects, most importantly, it means that NHibernate can apply quite a few optimizations for this process.

MVC - refresh controller SQL data model from View?

I am new to MVC, have some experience in webforms.
I currently have an ActionResult function in my controller that binds all my SQL data to a model, which then I can then successfully build a dataview from in the view.
My issue is that to have everything work properly, I need to call my ActionResult directly in the controller before rendering the page, and this works just fine:
public ActionResult Index()
{
Bind_grid();
return View();
}
public class My_Table
{
public string info_a { get; set; }
public string info_b { get; set; }
public string mod_id { get; set; }
}
public ActionResult Bind_grid()
{
SqlConnection checkitem = new SqlConnection("Data Source=[IPADDRESS];Persist Security Info=True;User ID=userid;Password=password");
string query = "SELECT id, info_a, info_b FROM [my_db].[dbo].[ref_index]";
SqlCommand execute = new SqlCommand(query, checkitem);
var model = new List<My_Table>();
using (checkitem)
{
checkitem.Open();
SqlDataReader rdr = execute.ExecuteReader();
while (rdr.Read())
{
var table = new My_Table();
table.info_a = rdr["info_a"].ToString();
table.info_b = rdr["info_b"].ToString();
table.mod_id = rdr["id"].ToString();
model.Add(table);
}
checkitem.Close();
}
return View(model);
}
I am wondering how to refresh the model from the view instead of requiring it to be ran before returning the view, I've tried AJAX calls and #HTML.Action calls to Bind_grid, but I can't seem to get the page to refresh the data.
Any suggestions in running Bind_grid from a view to refresh the model?
Currently I try this:
function bind_data() {
$.ajax({
url: '#Url.Action("Bind_grid")',
method: 'POST',
});
#{
int p = 0;
foreach (var d in Model)
{
#:console.log(#d.mod_id);
p++;
}
}
}
And I set a javascript interval for 10 seconds to run the bind_data() function,
remove some IDs from the SQL database between intervals,
but the data written to the console is still the original fetched, not the refreshed data.
If I manually refresh the page (F5), I get a correct update of data.
I'm guessing I need to do some kind of partial postback to refresh the razor data, but am not sure the best way to do it in MVC. Any help is appreciated.
You should be able to use the jquery load method, call in your JavaScript interval
$("#grid").load("bind_grid");
Fixed the issue by doing all processing in the codebehind, changed the Bind_grid()
to JsonResult, returning Json(model.ToArray(), JsonRequestBehavior.AllowGet);
Was able to do successful pulls via ajax request.

Gathering Active Directory Data for MVC intranet application

I need assistance with gathering Active Directory data based on a table in my DB. I have an entity class that holds user requests. Each request has the user's windows name from System.Web.HttpContext.Current.User.Identity.Name. My problem is I cannot figure out how to setup a linq query to associate the AD username to the rest of the AD so I can display their full names instead of their username in my table. Here is what I have so far, any help will be appreciated.
public partial class RequestInfo
{
public int RequestInfoId { get; set; }
public string RequestByUserADId { get; set; }
public System.DateTime RequestDateTime { get; set; }
public string Explanation { get; set; }
public virtual UserInfo UserInfo { get; set; } // where I define my custom roles
}
I can query AD by using the code below. I have tried Get Active Directory User Information With Windows Authentication in MVC 4, but it did not help.
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, requestByAdId))
{
return user.DisplayName
}
I may be off here because I am not sure if you are able to successful establish a user principal or not but if you have the user principal you can get property information like the following:
user.GetProperty("propertyName")
Here is a static method that should get you the department for a user, for example.
public static String GetDepartment(UserPrincipal principal)
{
return principal.GetProperty("department");
}
Let me know where this gets you and I can elaborate further if this isn't working.
Edit
It appears you need to go one level deeper to get the fields that aren't by default a part of the user principal. For this you will need to get the directory entry from the user principal first:
DirectoryEntry directoryEntry = (userPrincipal.GetUnderlyingObject() as DirectoryEntry);
Then you need to check if the attribute you are looking for exists, and if it does, get the value. A great way to do this is to create a helper method that you pass your directory entry to along with the string value for the property name that you want to get.
public string GetProperty(DirectoryEntry directoryEntry, string propertyName)
{
if (directoryEntry.Properties.Contains(propertyName))
{
return directoryEntry.Properties[propertyName][0].ToString();
}
else
{
return string.Empty;
}
}
Please note that going to the underlying object is expensive. I believe this operation, by default, is cached for you so subsequent use of this information can be retrieved from cache. Playing around with
directoryEntry.RefreshCache
will get you started with that.
Let me know if this does the trick for you!

Insertion failed when used Asp.Net Mvc, Linq, Entity Framework

I am trying to add row to table using asp.net mvc kendo ui. But for the first time, it is a success. when do second time, the debugging pointer says "The process or thread has been changed since the last step" and try to add the first insertion values also. Since the table does not allow the duplication of primary key the insertion fails at second time. Please advie.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Insert([DataSourceRequest] DataSourceRequest request, AdminHeaderImage batchModel)
{
if (ModelState.IsValid)
{
using (var Entity = new DealerEntities())
{
Entity.AdminHeaderImages.AddObject(batchModel);
Entity.SaveChanges();
return RedirectToAction("Index");
}
}
else
{
return RedirectToAction("Index");
}
}
public ActionResult Index()
{
using (var Entity = new DealerEntities())
{
var outPut = Entity.AdminHeaderImages.ToList();
return View(outPut);
}
}
It seems your Entity object is shared between requests.
I recommend having an entity object per web request.
This article explains more
http://blogs.microsoft.co.il/blogs/gilf/archive/2010/05/18/how-to-manage-objectcontext-per-request-in-asp-net.aspx
I just used the following code at the end of Insert which would refresh my entity.
"return Json(new [] { product }.ToDataSourceResult(request, ModelState));"
This solved my problem.