Why is C# and MongoDB Driver code connecting, but failing to Write? - c#

Here is the information about my development environment:
Microsoft Visual Studio Community 2015
.NET Framework 4.6
ASP.NET MVC assembly System.Web.Mvc Version=5.2.3.0
MongoDB.Driver 2.0.1.27
Mongodb 3.0.6
Within my C# application, I have the following code that retrieves a MongoDB database reference:
public class MongoDBConnectionManager {
public IMongoDatabase getMongoDB() {
var client = new MongoClient("mongodb://localhost:27017");
MongoClient(System.Configuration.ConfigurationManager.ConnectionStrings["MongoDB"].ConnectionString);
MongoServer.Create("Server=localhost:27017");
IMongoCollection <BsonDocument> UserDetails = iMgDb.GetCollection<BsonDocument>("Users");
return iMgDb;
}
}
Here is the POCO class that represent a User Business Entity:
using MongoDB.Bson.Serialization.Attributes;
public class UserModel {
[BsonId]
public int ID { get; set; }
[Required]
[BsonElement]
public string UserName { get; set; }
[Required]
[BsonElement]
public string Password { get; set; }
[Required]
[BsonElement]
public string Email { get; set; }
[BsonElement]
public string PhoneNo { get; set; }
[BsonElement]
public string Address { get; set; }
}
Here is the DAO C# class that uses the Mongo DB Connection Manager Class:
public class DAO {
public async Task<int> insertNewUser(UserModel um) {
MongoDBConnectionManager mgoDBCntMng = new MongoDBConnectionManager();
IMongoDatabase database = mgoDBCntMng.getMongoDB();
IMongoCollection <UserModel> UserDetails = database.GetCollection<UserModel>("Users");
try {
Task getTask = UserDetails.InsertOneAsync(um);
await getTask;
} catch(Exception) {
}
return 0;
}
}
When I run the application, I can see the following information logged in the DOS Command Prompt window where I started the mongoDB. If you look towards the end of the Dos Command Prompt, you will notice 2 connections being made:
C:\Program Files\MongoDB\Server\3.0\bin>mongod --dbpath ./data/db
2015-09-23T12:23:07.896+0530 I JOURNAL [initandlisten] journal
dir=./data/db\jo
urnal
2015-09-23T12:23:07.900+0530 I JOURNAL [initandlisten] recover : no
journal fil
es present, no recovery needed
2015-09-23T12:23:08.060+0530 I JOURNAL [durability] Durability thread started
2015-09-23T12:23:08.062+0530 I JOURNAL [journal writer] Journal writer thread s
tarted
2015-09-23T12:23:08.283+0530 I CONTROL [initandlisten] MongoDB starting
: pid=1
2936 port=27017 dbpath=./data/db 64-bit host=My-PC
2015-09-23T12:23:08.283+0530 I CONTROL [initandlisten] targetMinOS:
Windows 7/W
indows Server 2008 R2
2015-09-23T12:23:08.284+0530 I CONTROL [initandlisten] db version v3.0.6
2015-09-23T12:23:08.284+0530 I CONTROL [initandlisten] git version:
1ef45a23a4c
5e3480ac919b28afcba3c615488f2
2015-09-23T12:23:08.284+0530 I CONTROL [initandlisten] build info:
windows sys.
getwindowsversion(major=6, minor=1, build=7601, platform=2,
service_pack='Servic
e Pack 1') BOOST_LIB_VERSION=1_49
2015-09-23T12:23:08.285+0530 I CONTROL [initandlisten] allocator:
tcmalloc
2015-09-23T12:23:08.285+0530 I CONTROL [initandlisten] options: {
storage: { db
Path: "./data/db" } }
2015-09-23T12:23:08.321+0530 I NETWORK [initandlisten] waiting for
connections
on port 27017
2015-09-23T12:24:20.326+0530 I NETWORK [initandlisten] connection
accepted from
127.0.0.1:65065 #1 (1 connection now open)
2015-09-23T12:24:22.332+0530 I NETWORK [initandlisten] connection
accepted from
127.0.0.1:65066 #2 (2 connections now open)
I'm really stumped as to how to resolve the problem. I tried to search the MongoDB error log using DOS command prompt, but it shows NO errors.
From MongoDB client using DOS command prompt, I got the following:
C:\Program Files\MongoDB\Server\3.0\bin>mongo
MongoDB shell version: 3.0.6
connecting to: test
> use foo
switched to db foo
> db.runCommand( { getLastError: 1, w: 1, wtimeout:5000 } )
{
"connectionId" : 6,
"n" : 0,
"syncMillis" : 0,
"writtenTo" : null,
"err" : null,
"ok" : 1
}
The problem that I am facing is that the point of execution runs smoothly, but fails to write to the database.
What is wrong with the way I use async and wait in the said code?
Could someone please tell me how to correct the problem?

From MSDN
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.
So await does suspend or block until the task is completed so we just create multiple tasks and make sure we don't await it until we think we need to, if you are dealing with collection of inserts?
var tasks = new Task<//return type of UserDetails.InsertOneAsync(um)>[//get collection count here];
var count = 0;
foreach(// iterate collection here)
{
try {
tasks[count] = UserDetails.InsertOneAsync(um); // adds continuations and return back immediately i.e. no blocking
count++;
} catch(Exception) {
}
}
await Task.WhenAll(tasks.ToArray()); // here is where we block all tasks and wait for completion
Note: Not exactly answer but will somewhat clear what we are doing

There are some problem with your getMongoDB function code:
No need of making two connection use only one
IMongoClient is used to get database in Mongo.Driver 2.0.1.17. No need of Making "MongoServer"
No need of getting collection in "getMongoDB" function
Here is the code for "getMongoDB" function:
public IMongoDatabase getMongoDB()
{
IMongoClient client = new MongoClient("mongodb://localhost:27017");
var iMgDb = client.GetDatabase("Database Name Here");
return iMgDb;
}
Hope this will help.

It took a while, but the problem was caused by the fact that I mistakenly used the int basic data type for the ID in the UserModel as opposed to ObjectId.
Here is the corrected code for the UserModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using WebApplication1.Models;
using MongoDB.Bson.Serialization.Attributes;
namespace WebApplication1.Models
{
public class UserModel
{
[BsonId]
public ObjectId ID { get; set; }
[Required]
[BsonElement]
public string UserName { get; set; }
[Required]
[BsonElement]
public string Password { get; set; }
[Required]
[BsonElement]
public string Email { get; set; }
[BsonElement]
public string PhoneNo { get; set; }
[BsonElement]
public string Address { get; set; }
}
}

Related

Using a Database Context in multiple projects within the same solution

I'm currently working on a program that is being used to generate PDF's and documents. There are two different use cases, one being an automated process and the second being a manual process where data can be edited via a front-end app.
The solution has 2 Projects in it, the first for the automated part, and the second for the manual part.
However, since the two processes make use of the same data and templates, I've split the solution into two parts, this will allow me to set it up in a way in which I only need to maintain models/templates once.
My database context looks like this:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RefundTracker.Models
{
public class DatabaseContext : DbContext
{
public DatabaseContext()
:base("Prod")
{
}
public DbSet<Referral> Referrals { set; get; }
public DbSet<ReferralAppointment> ReferralAppointments { set; get; }
public DbSet<ReferralPayment> ReferralPayments { set; get; }
public DbSet<BankDetails> BankDetails { set; get; }
public DbSet<ReferralAppointment_History> ReferralAppointment_History { set; get; }
public DbSet<ReferralPayment_History> ReferralPayment_History { set ; get; }
public DbSet<IsInUse> IsInUse { set; get; }
}
}
In terms of projects, I have a project called "RefundTracker" and another called "MailMergeTPA".
The context provided above, together with all of the models, are located in the "RefundTracker" project.
I would like to make use of these models and context in the "MailMargeTPA" project as well.
I referenced the "RefundTracker" in "MailMergeTPA" project, however, no results when using the context here. (When I access a function that get a list of names for instance, I get the full list in "RefundTracker", however, I get no results when I use the same function in "MailMergeTPA".
Code Example:
public BankDetails GetBankDetails(Referral record)
{
string bName = record.bankName.Trim();
try
{
BankDetails bankDetails= new BankDetails();
List<BankDetails> bankDetails = new List<BankDetails>();
using (DatabaseContext db = new DatabaseContext())
{
bankDetails = db.BankDetails.SingleOrDefault(a => a.BankName == bName);
}
return bankDetails;
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
return null;
}
I would like to make use of this exact function in both projects.
Could you kindly help me with some advice? (Please go easy on me in the comments, I'm still fairly new to EF)
I've tried referencing the project, no result.
I've read up on interfaces, however, I'm unsure as to how I would incorporate this.

Azure C# Cosmos DB: Required property 'id' missing when inserting data

I am creating a program that writes data into a Cosmos DB (OneAuthZDeltaRoleDatabase), however, when I write data, I receive the following error:
"The input content is invalid because the required properties - 'id; ' - are missing"
Below is my code where I programmatically create the Cosmos DB (OneAuthZDeltaRoleDatabase) and its container (OneAuthZDeltaRoleContainer), and attempt to insert the data into the Cosmos DB (the database and the container are successfully created, but inserting data is unsuccessful):
// Creates the Cosmos DB database where we store the last delta API call for each app
private static async Task CreateDeltaAPICallDatabaseAsync()
{
// Create a new database
lastAPICallDatabase = await cosmosClient.CreateDatabaseIfNotExistsAsync(lastDeltaDatabaseId);
}
// Creates the Cosmos DB container where we store the last delta API for each app
private static async Task CreateDeltaAPICallContainerAsync()
{
// Create a new container
lastAPICallContainer = await lastAPICallDatabase.CreateContainerIfNotExistsAsync(lastDeltaContainerId, "/AppId");
}
/* Timer function that reads the role assignments table (OneAuthZRoleAssignments) on a configurable schedule
* and computes + displays a mapping of users to their corresponding role assignments (e.x. every 2 mins) */
[FunctionName("InitiateChangeMonitoring")]
public static async Task InitiateChangeMonitoring([TimerTrigger("%TimerTriggerPeriod%")] TimerInfo myTimer, ILogger log)
{
// Create the necessary Cosmos DB infastructure
await CreateDeltaAPICallDatabaseAsync();
await CreateDeltaAPICallContainerAsync();
foreach (string appId in oneAuthZAppIds)
{
// Initialize the base delta API call timestamp for that app id (if it does not exist)
await lastAPICallContainer.CreateItemAsync(new DeltaAPIMapping(appId, baselineSnapshotTime), new PartitionKey(appId));
}
}
This is the code for the DeltaAPIMapping class (the class I am adding to the Cosmos DB).
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace AccessChangeMonitoring
{
class DeltaAPIMapping
{
[JsonProperty(PropertyName = "AppId")]
public string id { get; set; }
public DeltaAPIMapping(string appId, DateTime callTimestamp)
{
this.id = Guid.NewGuid().ToString();
this.appId = appId;
this.callTimestamp = callTimestamp;
}
public string appId { get; set; }
public DateTime callTimestamp { get; set; }
}
}
I had the same issue and I had changed my property from string to Guid and now it works.
class DeltaAPIMapping
{
[JsonProperty(PropertyName = "id")]
public Guid MyIdWithAnotherName { get; set; }
The important part is:
Your document has to have an id Property, this "id" is going to store a Guid value,
If it doesn't exist (I mean a property with that name) then you may use the Json Annotations to setup any Guid property as a Json Property with the name "id", this annotation is going to map all the references to "id" (from the JsonDocument) and store them in "MyIdWithAnotherName", this is how it works in my example.
Additionally, maybe if you use a string instead of Guid is going to work too but I have not tested that way.
You need the JsonProperty name to be "id", not "AppId". If AppId is what your app needs, then try flipping these and trying again.

C# SQL Server input [duplicate]

This question already has an answer here:
Bad Storage property: unknown cause
(1 answer)
Closed 7 years ago.
I am testing using a SQL database in C#. I followed the instructions from the MSDN to doing so. Here is the code:
using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LinqConsoleApp
{
[Table(Name = "DesanoDict1")]
public class DesanoDict1
{
[Column(Storage = "_Desano")]
public string Desano
{
get;
set;
}
[Column(Storage = "_Portuguese")]
public string Portuguese
{
get;
set;
}
[Column(Storage = "_English")]
public string English
{
get;
set;
}
[Column(Storage = "_Spanish")]
public string Spanish
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
// Use a connection string.
DataContext db = new DataContext
(#"C:\Users\FieldLingLab\Documents\Visual Studio 2015\Projects\GUI Test\GUI Test\Resources\Desano\Desano.mdf");
Table<DesanoDict1> dd1 = db.GetTable<DesanoDict1>();
IQueryable<DesanoDict1> DesQuery = from des in dd1
select des;
foreach(DesanoDict1 dd in DesQuery)
{
Console.WriteLine("Desano={0}, Portuguese={1}. English={2}, Spanish={3}", dd.Desano, dd.Portuguese, dd.English, dd.Spanish);
}
Console.ReadLine();
}
}
}
The database is an mdf file from SQL Server 2014. It's a table with four columns (Desano, Portuguese, English, Spanish) and they each have words them in (I believe) UTF-16 encoding (nvarchar in SSMS). The problem I'm getting is that when I run, I get a runtime error on the GetTable line saying "Bad storage property: "_Desano."" Where did I go wrong here?
Not sure because I didn't run it, but according to the msdn example it looks like you actually need to define the storage private field. like so
private string _Desano;
[Column(Storage = "_Desano")]
public string Desano
{
get;
set;
}

Neo4JClient Cyper.Create Deprecated

I have just started to explore Graph databases and Neo4jClient library for Neo4J. I am using Neo4JClient v1.1.0.11 downloaded from NuGet in Visual Studio. I want to create a Node in Neo4J and for that I am using this code (C#):
var client = new GraphClient(new Uri("http://localhost:7474/db/data"), "user", "pass");
client.Connect();
client.Cypher.Create();
But on Cypher.Create Intellisense shows that it is deprecated. My question is what is the alternate way of creating a Node? An example would be appreciated.
In this particular case I have a User that I want to create in the database. The class looks like:
public class User
{
public Int32 ID { get; set; }
public String UserName { get; set; }
public String Name { get; set; }
public Boolean Active { get; set; }
public String Email { get; set; }
public String Password { get; set; }
}
Thanks
I believe only one overload on the Create method has been marked as obsolete - unless there is something I am not aware of. The following code should do what you need and does not show as being deprecated.
var client = new GraphClient(new Uri("http://localhost:7474/db/data"), "user", "pass");
client.Connect();
var user = new User
{
// initialise properties
};
client.Cypher
.Create("(u:User {user})")
.WithParams(new { user = user })
.ExecuteWithoutResults();
There are a number of variations on this that will work but it should get you started.
As an aside, were you to use the first overload on the Create method you would indeed see it marked as deprecated. For example, this code
client.Cypher
.Create("(u:User {0})", user)
.ExecuteWithoutResults();
would give you the following warning in Visual Studio
'Neo4jClient.Cypher.ICypherFluentQuery.Create(string, params object[])' is obsolete: 'Use Create(string) with explicitly named params instead. For example, instead of Create("(c:Customer {0})", customer), use Create("(c:Customer {customer})").WithParams(new { customer }).'

MVC 4.0 Controller cannot find seeded data

I am attempting to seed data for an MVC 4 project using SQL server 4.0 as the database engine, using the Microsoft MVC music store tutorial as an example. I have set up a seed and DB context models, but the controller is not able to find the data. I have verified that the the database file is created in App_Data and verified that SetIntitializer is correctly set up in Application_Start. Here is what I have for code:
Seed data:
namespace RationalMethodApp.Models
{
public class StartData : CreateDatabaseIfNotExists<RationalMethodEntities>
{
protected override void Seed(RationalMethodEntities context)
{
new List<Basin>
{
new Basin {
basinId = 1, // attempting to force a key value, will remove
Name = "Replace me with a real basin",
Location = "In a real location",
drainageArea = 0.0M
}
}.ForEach(b => context.Basins.Add(b));
Controller:
public ActionResult Index(int? bsnId)
{
if (bsnId == null) // here to force a key value, will change
bsnId = 1;
var basin = rmDb.Basins.Find(bsnId);
return View(basin);
}
The context class is:
namespace RationalMethodApp.Models
{
public class RationalMethodEntities : DbContext
{
public DbSet<Basin> Basins { get; set; }
public DbSet<SubArea> SubAreas { get; set; }
public DbSet<IdfCurve> IdfCurves { get; set; }
public DbSet<Analysis> Analyses { get; set; }
public DbSet<FlowSegment> FlowSegments { get; set; }
public DbSet<SheetFlowN> SheetFlowNs { get; set; }
public DbSet<RunoffCoefficient> RunoffCoefficients { get; set; }
public DbSet<StormFrequency> stormFrequencies { get; set; }
}
}
The debugger tells me that the "basin" object is still null in the controller after the .Find. This must be a simple, basic thing that I have overlooked, but all of the help I can find on-line assumes that the askers know what they are doing - not true in my case! I have also checked the discussion at Entity Framework database seed doesn't seed
but this does not seem to be the answer. Please bear with a total noob question.
You don't show the full code of you seed, so i can't really be sure, but you might be missing the Context.Changes().
As well you wrote
public class StartData : CreateDatabaseIfNotExists<RationalMethodEntities>
If you don't delete your database before the application start, it won't do anything as the db already exists.
You could use :
public class StartData : DropCreateDatabaseAlways <RationalMethodEntities>
to drop it every time you start or
public class StartData : DropCreateDatabaseAlways <DropCreateDatabaseIfModelChanges >
to drop db when Model changes (which is great for start of dev)
To debug: Drop your database, kill your application server (so it goes back to application start), breakpoint in your seed. Start Debug, if it goes in seed, check that data is in it after SaveChange().

Categories