I'm fairly new to C# programming but am competent in SQL. I'm trying to write my first application (a data monitoring system) which saves SQL statements and thresholds from user input then on a squeal, runs the statements and checks to see if they have breached their respective threshold, this then alerts the user on screen and also sends an email/text if applicable.
Here I have some code that grabs data from 2 tables (this is ASP.NET Core MVC so they are models):
Widget - Which is where the check information is kept (we only care about the statement and connection string id.
ConnectionStrings - Which is where each connection string is stored.
I'm trying to get it to pull back a list of the checks, then their corresponding connection string, pass them into SqlConnection or a Dapper method and log the results to a table where they can be passed back to the user.
The bit I'm stuck at is that GetConnectionStringId and Query, both of which throw the error mentioned in the title. Obviously I'm trying to do a foreach in the list, using .FistOrDefault is not the answer I'm looking for here unless anyone can properly explain why it should be. It turns my IEnumerable error into a bool error and should be needless to say none of these values are booleans.
Is there a simple way around this or am I going about this the completely wrong way?
Don't be shy with a response I'm quite happy to be told I've got no clue what I'm doing, thanks in advance!
Also if more information is needed please let me know!
using Dapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Data;
using SystemBoard.Data;
namespace SystemBoard.Controllers
{
public class WidgetCheckController : Controller
{
private readonly ApplicationDbContext _context;
public WidgetCheckController(ApplicationDbContext context)
{
_context = context;
}
// * Testing with list idea
public async Task<List<IActionResult>> GetCheckResult()
{
var checks = await _context.Widget
.Where(x => x.DateDeleted == null)
.ToListAsync();
foreach (var WidgetId in checks)
{
var GetConnectionStringId = checks.Select(x => x.ConStringId);
var ActualConnectionString = _context.ConnectionStrings.First(x => x.ConnectionStringId = GetConnectionStringId);
// I don't know if it's better to write it like this? I get the same error under 'checks.Select(x => x.ConStringId)'
// var ActualConnectionString = _context.ConnectionStrings.First(x => x.ConnectionStringId = checks.Select(x => x.ConStringId));
var Query = checks.Select(x => x.SQLStatement);
using (IDbConnection connection = ActualConnectionString)
{
connection.Query(Query);
}
}
}
}
}
i have a MongoDB Database for my discord but i'm making a simple c# app that will access the database and show each users name and level this is my current code
using MongoDB.Bson;
using MongoDB.Driver;
namespace ExampleApp
{
class Program
{
static async Task Main()
{
MongoClient dbClient = new MongoClient("Connection String");
var database = dbClient.GetDatabase("test");
var collection = database.GetCollection<BsonDocument>("users");
var firstDocument = collection.Find(new BsonDocument()).ForEachAsync(user =>
{
Console.WriteLine(user);
});
Console.Read();
}
}
}
i can't figure out how to print each users name and level like user.name or user.level isn't a thing
You can access the properties of the BsonDocument like this:
Console.WriteLine($"{user["name"].AsString} - {user["level"].AsInt32}");
The indexer is used to retrieve the value. Based on this, you can use the As*-properties to convert the value to the desired data type. Above sample assumes that name is a string and level is an Int32 (int).
I am trying to send a login and a password and if it find in the DataBase it shold return the account details. But i am getting this error on my console:
ERROR HttpErrorResponse {headers: HttpHeaders, status: 500, statusText: "Internal Server Error", url: "http://localhost:56624/api/Usuarios"
And here is my API code:
`
public Usuarios Post([FromBody]LoginRequest login)
{
var usuario = new Usuarios();
var con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["comidas"].ConnectionString);
var com = new SqlCommand("SELECT * FROM usuarios WHERE loginUsuario = #loginUsuario AND senhaUsuario = #senhaUsuario", con);
com.Parameters.AddWithValue("#loginUsuario", login.loginUsuario);
com.Parameters.AddWithValue("#senhaUsuario", login.senhaUsuario);
con.Open();
var rdr = com.ExecuteReader();
if (rdr.HasRows)
{
usuario.idUsuario = (int)rdr["idUsuario"];
usuario.loginUsuario = (string)rdr["loginUsuario"];
usuario.senhaUsuario = (string)rdr["senhaUsuario"];
usuario.nomeUsuario = (string)rdr["nomeUsuario"];
usuario.emailUsuario = (string)rdr["emailUsuario"];
usuario.telefoneUsuario = (string)rdr["telefoneUsuario"];
return usuario;
}
con.Close();
return null;
}`
If you guys spot any mistake pleasse tell me, i am new to C#.
Here is the request code in javascript:
getUser() {
let head = new HttpHeaders();
head.set('Content-Type', 'application/json');
let body = {
loginUsuario: '*login*',
senhaUsuario: '*password*'
}
return this.http.post(this.url + 'Usuarios', body, { headers: head }).subscribe(data => {
this.user = data;
console.log(data);
});
}
and the classes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MeinNahrungAPI.Models
{
public class Usuarios
{
public int idUsuario;
public string loginUsuario;
public string senhaUsuario;
public string tipoUsuario;
public string nomeUsuario;
public string emailUsuario;
public string telefoneUsuario;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MeinNahrungAPI.Models
{
public class LoginRequest
{
public string loginUsuario;
public string senhaUsuario;
}
}
enter image description here
enter image description here
As a result of the comment thread on the question...
You're getting an exception here:
usuario.idUsuario = (int)rdr["idUsuario"];
I'm not familiar with the specific translation of the exception from your Portuguese settings, but essentially what it means is that you're attempting to read data when none is available. Which is slightly misleading, since there is data returned from the query (which is why rdr.HasRows resolves to true). But you haven't called rdr.Read() to access the first record in the results. Even if there's only one record, technically it's still a collection of records which happens to have only one entry. And a DataReader needs to be told to progress through that collection.
Take a look at some examples here. Specifically at how they structure reading the results:
while (reader.Read())
{
//...
}
In this case calling .Read() returns a bool indicating whether or not there is a next record to read, but it also is quietly advancing the DataReader internally to access that next record.
You can use this same loop structure and expect it to only loop one time since there should be only one returned record. (It wouldn't hurt to add in some error checking to handle unexpected possibilities if more than one record is returned.) Or you could even just call .Read() once:
if (rdr.HasRows)
{
rdr.Read();
// the rest of your code
}
Another thing to note, which is unrelated to the problem but is important regardless. First off, as a beginner, the fact that you're using query parameters instead of directly concatenating string values is a very good thing. However, there's another security problem in your code that you should be made aware of. You are storing user passwords in plain text. This is a very bad thing. You don't want to be able to ever see or know your users' passwords.
There are existing authentication tools in the .NET Framework which can do much of the work for you. But even when creating your own, you should always hash the passwords. (Not encrypt, hash. It's a very important distinction.) And with good hashing methods (not MD5). That way nobody can ever recover the original password. Not an attacker, not even you as the system owner.
I'm new to Entity Framework (working mostly with NHibernate with ActiveRecord before) and I'm stuck with something, that I think should be easy...
I have a User Entity, and created partial User class so I can add some methods (like with NHibernate). I added GetByID to make getting user easier:
public static User GetByID(int userID)
{
using (var context = new MyEntities())
{
return context.Users.Where(qq => qq.UserID == userID).Single();
}
}
Now in the same class I want to log moment of logging in, and I try to do:
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = User.GetByID(userID);
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.SaveChanges();
}
}
The problem is I can't access user.LoginLogs because user's context is already disposed... Most likely I'm missing something obvious here, but creating always full queries like:
context.Users.Where(qq => qq.UserID == userID).Single().LoginLogs.Add(log);
doesn't seem like a good option...
I've read about Repository pattern but I think it's too big gun for such task. Please explain me what am I doing wrong. Thanks in advance!
EDIT
To picture what I'd like to do:
//somewhere in business logic
var user = User.GetByID(userID);
var posts = user.GetAllPostsForThisMonth();
foreach(var post in posts)
{
Console.WriteLine(post.Answers.Count);
}
Normally I'm not allowed to do this because I can't get post.Answers without context...
You are closing the object context and then trying to add a log to the user that is detached. You need to attach the user so the objectContext know what has been changed or added.
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = context.User.Where(p=>p.UserID == userID); //<= The Context now knows about the User, and can track changes.
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.SaveChanges();
}
}
Update
You can also attach the object.
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = User.GetByID(userID);
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.User.Attach(user);
context.SaveChanges();
}
}
Update
var getFirstLogin = from p in User.GetUserById(userId)
select p.LoginLogs.FirstOrDefault();
NB if LoginLogs is a different table you will need to use Include.
public static User GetByID(int userID)
{
using (var context = new MyEntities())
{
return context.Users.Include("LoginLogs").Where(qq => qq.UserID == userID).FirstOrDefault();
}
}
If you are open to using stored procedures (and they work nicely with EF), you can return the user object and simultaneously add to the log table with a single call to the database.
I used to do everything with SP's in my pre-EF/ORM days, when I went to EF I tried very hard to avoid using stored procedures to avoid falling back into my old habits, but now I have found that the selective use of stored procedures you can have the benefits of both -the EF way of doing things, and the super functionality/performance that a well written SP can provide.
I develops a C# Winform application, it is a client and connect to web service to get data. The data returned by webservice is a DataTable. Client will display it on a DataGridView.
My problem is that: Client will take more time to get all data from server (web service is not local with client). So I must to use a thread to get data. This is my model:
Client create a thread to get data -> thread complete and send event to client -> client display data on datagridview on a form.
However, when user closes the form, user can open this form in another time, and client must get data again. This solution will cause the client slowly.
So, I think about a cached data:
Client <---get/add/edit/delete---> Cached Data ---get/add/edit/delete--->Server (web service)
Please give me some suggestions.
Example: cached data should be developed in another application which is same host with client? Or cached data is running in client.
Please give me some techniques to implement this solution.
If having any examples, please give me.
Thanks.
UPDATE : Hello everyone, maybe you think my problem so far. I only want to cache data in client's lifetime. I think cache data should be stored in memory. And when client want to get data, it will check from cache.
If you're using C# 2.0 and you're prepared to ship System.Web as a dependency, then you can use the ASP.NET cache:
using System.Web;
using System.Web.Caching;
Cache webCache;
webCache = HttpContext.Current.Cache;
// See if there's a cached item already
cachedObject = webCache.Get("MyCacheItem");
if (cachedObject == null)
{
// If there's nothing in the cache, call the web service to get a new item
webServiceResult = new Object();
// Cache the web service result for five minutes
webCache.Add("MyCacheItem", webServiceResult, null, DateTime.Now.AddMinutes(5), Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);
}
else
{
// Item already in the cache - cast it to the right type
webServiceResult = (object)cachedObject;
}
If you're not prepared to ship System.Web, then you might want to take a look at the Enterprise Library Caching block.
If you're on .NET 4.0, however, caching has been pushed into the System.Runtime.Caching namespace. To use this, you'll need to add a reference to System.Runtime.Caching, and then your code will look something like this:
using System.Runtime.Caching;
MemoryCache cache;
object cachedObject;
object webServiceResult;
cache = new MemoryCache("StackOverflow");
cachedObject = cache.Get("MyCacheItem");
if (cachedObject == null)
{
// Call the web service
webServiceResult = new Object();
cache.Add("MyCacheItem", webServiceResult, DateTime.Now.AddMinutes(5));
}
else
{
webServiceResult = (object)cachedObject;
}
All these caches run in-process to the client. Because your data is coming from a web service, as Adam says, you're going to have difficulty determining the freshness of the data - you'll have to make a judgement call on how often the data changes and how long you cache the data for.
Do you have the ability to make changes/add to the webservice?
If you can Sync Services may be an option for you. You can define which tables are syncronised, and all the sync stuff is managed for you.
Check out
http://msdn.microsoft.com/en-us/sync/default.aspx
and shout if you need more information.
You might try the Enterprise Library's Caching Application Block. It's easy to use, stores in memory and, if you ever need to later, it supports adding a backup location for persisting beyond the life of the application (such as to a database, isolated storage, file, etc.) and even encryption too.
Use EntLib 3.1 if you're stuck with .NET 2.0. There's not much new (for caching, at least) in the newer EntLibs aside from better customization support.
Identify which objects you would like to serialize, and cache to isolated storage. Specify the level of data isolation you would like (application level, user level, etc).
Example:
You could create a generic serializer, a very basic sample would look like this:
public class SampleDataSerializer
{
public static void Deserialize<T>(out T data, Stream stm)
{
var xs = new XmlSerializer(typeof(T));
data = (T)xs.Deserialize(stm);
}
public static void Serialize<T>(T data, Stream stm)
{
try
{
var xs = new XmlSerializer(typeof(T));
xs.Serialize(stm, data);
}
catch (Exception e)
{
throw;
}
}
}
Note that you probably should put in some overloads to the Serialize and Deserialize methods to accomodate readers, or any other types you are actually using in your app (e.g., XmlDocuments, etc).
The operation to save to IsolatedStorage can be handled by a utility class (example below):
public class SampleIsolatedStorageManager : IDisposable
{
private string filename;
private string directoryname;
IsolatedStorageFile isf;
public SampleIsolatedStorageManager()
{
filename = string.Empty;
directoryname = string.Empty;
// create an ISF scoped to domain user...
isf = IsolatedStorageFile.GetStore(IsolatedStorageScope.User |
IsolatedStorageScope.Assembly | IsolatedStorageScope.Domain,
typeof(System.Security.Policy.Url), typeof(System.Security.Policy.Url));
}
public void Save<T>(T parm)
{
using (IsolatedStorageFileStream stm = GetStreamByStoredType<T>(FileMode.Create))
{
SampleDataSerializer.Serialize<T>(parm, stm);
}
}
public T Restore<T>() where T : new()
{
try
{
if (GetFileNameByType<T>().Length > 0)
{
T result = new T();
using (IsolatedStorageFileStream stm = GetStreamByStoredType<T>(FileMode.Open))
{
SampleDataSerializer.Deserialize<T>(out result, stm);
}
return result;
}
else
{
return default(T);
}
}
catch
{
try
{
Clear<T>();
}
catch
{
}
return default(T);
}
}
public void Clear<T>()
{
if (isf.GetFileNames(GetFileNameByType<T>()).Length > 0)
{
isf.DeleteFile(GetFileNameByType<T>());
}
}
private string GetFileNameByType<T>()
{
return typeof(T).Name + ".cache";
}
private IsolatedStorageFileStream GetStreamByStoredType<T>(FileMode mode)
{
var stm = new IsolatedStorageFileStream(GetFileNameByType<T>(), mode, isf);
return stm;
}
#region IDisposable Members
public void Dispose()
{
isf.Close();
}
}
Finally, remember to add the following using clauses:
using System.IO;
using System.IO.IsolatedStorage;
using System.Xml.Serialization;
The actual code to use the classes above could look like this:
var myClass = new MyClass();
myClass.name = "something";
using (var mgr = new SampleIsolatedStorageManager())
{
mgr.Save<MyClass>(myClass);
}
This will save the instance you specify to be saved to the isolated storage. To retrieve the instance, simply call:
using (var mgr = new SampleIsolatedStorageManager())
{
mgr.Restore<MyClass>();
}
Note: the sample I've provided only supports one serialized instance per type. I'm not sure if you need more than that. Make whatever modifications you need to support further functionalities.
HTH!
You can serialise the DataTable to file:
http://forums.asp.net/t/1441971.aspx
Your only concern then is deciding when the cache has gone stale. Perhaps timestamp the file?
In our implementation every row in the database has a last-updated timestamp. Every time our client application accesses a table we select the latest last-updated timestamp from the cache and send that value to the server. The server responds with all the rows that have newer timestamps.