I'm having trouble publishing my Entity Framework database to azure.
I'm working with .NET framework 4.5 and EF 6.1.3. The way my project is set up is as follows and using a code first approach:
Class library for the domain entities(database entities)
Class library for the DTOs
Class library for a repository where I do all the CRUD operations with Entity
Web api project for just the web services(there's no presentation, just restful controllers).
My web services project has references to the repository library and the DTOs library and I never created the database explicitly because EF created it for me using SQL server express I believe, I set up the web.config as follows:
<connectionStrings>
<add name="Database" connectionString="Server=(localdb)\v11.0;Database=Database;Trusted_Connection=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
In my project the database is created along with all the tables and relationships. I added some initial migrations in the repository library like this
namespace Project.Repository.Migrations
{
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;
internal sealed class Configuration : DbMigrationsConfiguration<Project.Repository.ProjectContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(Project.Repository.ProjectContext context)
{
Guid userId = new Guid();
Guid restaurantId = new Guid();
context.Users.AddOrUpdate(
u => u.Id, new Domain.Security.User { Id = userId, Age = 18, Description = "I like restaurants", Email = "user#gmail.com", Password = "12345", Username = "someuser" }
);
context.Restaurants.AddOrUpdate(
r => r.Id,
new Domain.Restaurants.Restaurant
{
Id = restaurantId,
Name = "mcdonalds",
Description = "best restaurant",
FacebookUrl = "www.facebook.com",
GoogleUrl = "www.google.com",
InstagramUrl = "www.instagram.com",
TwitterUrl = "www.twitter.com",
Votes = 3.5f,
UsersWhoLike = new List<Domain.Security.User>() { context.Users.FirstOrDefault(u => u.Id == userId) }
}
);
context.SaveChanges();
}
}
}
When I set to publish the project to my azure websites the webservices publish allright but the database doesn't or at least whenever I call the restaurants service with website/api/restaurants which is the route for getting a list of restaurants it says.
{"Message":"An error has occurred."}
My azure database connection string is setup like this:
Data Source=tcp:someidentifier.database.windows.net,1433;Initial Catalog=Database;Integrated Security=False;User ID=Database#someidentifier;Password=xxxxxx;Connect Timeout=30;Encrypt=True
I don't know what is happening and I don't know if azure is actually seeding the database, what did I left out or what could be my mistakes?
First of all, go to your asp.net webconfig and set this value to Off:
<system.web><customErrors mode="Off"/></system.web>
You'll get an informative Yellow Screen of Death and have a chance of figuring out what's actually wrong. If the YoD is unclear, post it on your answer.
To can see exceptions in azure portal go to your web app -> Tools -> Troubleshoot -> Live HTTP traffic, select Analyze.
Related
I am new to C# and Serverless development. I am trying to create an AWS Lambda that has an API Gateway trigger. When the Lambda triggers I want to write a User record to the database.
Lambda:
namespace CreateProfile;
using System.Net;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using Database;
using Users.Models;
public class Function
{
/// <summary>
/// This Lambda function is for creating a user profile
/// </summary>
public APIGatewayHttpApiV2ProxyResponse FunctionHandler(User user, ILambdaContext context)
{
LambdaLogger.Log($"Calling function name: {context.FunctionName}\n");
LambdaLogger.Log($"Payload Received: {user}");
// 1. Populate the relevant table(s) from our input
using myDbContext ctx = new();
ctx.Users.Add(user);
ctx.SaveChanges();
APIGatewayHttpApiV2ProxyResponse response = new ()
{
StatusCode = (int)HttpStatusCode.OK,
Body = "Great Scott...it worked!",
Headers = new Dictionary<string, string> { { "Content-Type", "text/plain" } }
};
return response;
}
}
I am using the following Assembly:
using Amazon.Lambda.Core;
using Amazon.Lambda.Serialization.SystemTextJson;
// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(
DefaultLambdaJsonSerializer
))]
I am using the following as my database context:
namespace Database;
using Users.Models;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using Npgsql;
[DbConfigurationType(typeof(Config))]
public class MyDbContext: DbContext
{
public myDbContext(): base(MakeConnString()) {}
private static string MakeConnString()
{
// Will be moving these to a common location
string OptEnv(string key, string default_) =>
Environment.GetEnvironmentVariable(key) ?? default_;
string Env(string key) =>
Environment.GetEnvironmentVariable(key) ?? throw new MissingFieldException(key);
NpgsqlConnectionStringBuilder builder = new()
{
Host = Env("PGHOST"),
Port = int.Parse(OptEnv("PGPORT", "5432")),
SslMode = Enum.Parse<SslMode>(OptEnv("PGSSLMODE", "Require")),
TrustServerCertificate = true,
Database = OptEnv("PGDATABASE", "postgres"),
Username = OptEnv("PGUSER", "postgres"),
Password = Env("PGPASSWORD")
};
return builder.ConnectionString;
}
public DbSet<User> Users { get; set; }
}
When running this my Lambda hangs and I can't figure out why.
I'm assuming the database you are trying to interact with is an RDS instance or running on an EC2 instance in the same account, right?
If so, are your Lambda function deployed into your VPC? If not, the Lambda needs to be in order to talk to a VPC resource. The default is the Lambdas are NOT deployed in your VPC.
If you are using Serverless Framework then you need to add the following config to the provider section of your serverless.yml [https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml]
provider:
# Optional VPC settings
# If you use VPC then both securityGroupIds and subnetIds are required
vpc:
securityGroupIds:
- securityGroupId1
subnetIds:
- subnetId1
- subnetId2
The subnets you reference need to have a route to the subnets your database is provisioned into. They can be in the same subnets as the ones your RDS instance or EC2 is running the in DB.
Lastly, you need to ensure that the Security Group allows outbound traffic on the correct port for your Lambda Security Group, as well as, ensure that the Security Group on your database (EC2 or RDS) allows traffic from either the Lambda SG or the CIDR/IP ranges of the subnets you are deploying the Lambdas into on the correct port #.
The hanging is typically the request not making it to the DB - if you are already set up with your Lambda deployed in your VPC, then you should check the routing and Security Groups mentioned.
I am creating an ASP.Net MVC application and I have created a new console application just so that I can pass it a few parameters and use the DataContext in the MVC application so that I dont have to continually repeat myself.
This is the code that I am using
using mySite.WebSite.DataModel;
namespace mySite.AvailabilityManager
{
class Program
{
public static List<DateTime>Availability = new List<DateTime>();
static void Main(string[] args)
{
var startingDt = Convert.ToDateTime("04-09-2015 08:00:00");
var endingDt = Convert.ToDateTime("04-09-2015 17:00:00");
CreateAvailabilty(startingDt, endingDt);
AddAvailabilityToDatabase();
}
public static void CreateAvailabilty(DateTime startingDt, DateTime endingDt)
{
var hoursDiff = endingDt.Subtract(startingDt);
for (int i = 0; i < hoursDiff.Hours; i++)
{
Availability.Add(startingDt);
startingDt = startingDt.AddHours(1);
}
}
public static void AddAvailabilityToDatabase()
{
using (var db = new FitnessForAllContext())
{
foreach (var availableDate in Availability.Select(date => new AvailableDate {DateAvailable = date}))
{
db.AvailableDates.Add(availableDate);
db.SaveChanges();
}
}
}
}
When I get to db.AvailableDates.Add(..) I get this error
No connection string named 'MyDBContext' could be found in the application config file.
I was under the impression that because I am using the reference from my MVC application and the connection string is in the ASP.Net MVC config file that I would not have to repeat the connection string in my app.config file for the console application.
So, to summaries,
I have the MVC Project refernece in my console application
This fails because of the lack of a connection string at db.AvailableDates.Add(availableDate);
The mySite.Website assembly is being pulled through into my bin debug folder
If you could offer some insight as to what I need to do without having to continually repeat myself by adding the connection string everywhere I intend on using this, unless I REALLY have to repeat myself
Standard, the connection string needs to be in de config file of the startup project. In this case of the console application. The config of the referenced project is ignored.
You can have a constant or an embedded resource or anything IN your EntityFramework project that contains connection string. But I think, it's not a good practice, every executing project should have it's own configuration.
I've been following this tutorial http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application but customising it for a project I'm working on.
I'm having problems when I run it though - it fails to initialize the DB and gives me this error when I access a controller which needs to use the DB:
Failed to set database initializer of type 'JustSpecIt.DAL.JustSpecItInitializer, JustSpecIt' for DbContext type 'JustSpecIt.DAL.JustSpecItAppContext, JustSpecIt' specified in the application
My initializer and context files are in a DAL folder. In my webconfig file I have:
<entityFramework>
<contexts>
<context type="JustSpecIt.DAL.JustSpecItAppContext, JustSpecIt">
<databaseInitializer type="JustSpecIt.DAL.JustSpecItInitializer, JustSpecIt" />
</context>
And for my connection string I have:
<connectionStrings>
<add name="JustSpecItAppContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=JustSpecIt;Integrated Security=SSPI;" providerName="System.Data.SqlClient"/>
</connectionStrings>
I'm new to this so let me know if more info is required.
As requested, here is my initializer class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using JustSpecIt.Models;
namespace JustSpecIt.DAL
{
public class JustSpecItInitialiser : System.Data.Entity.DropCreateDatabaseIfModelChanges<JustSpecItAppContext>
{
protected override void Seed(JustSpecItAppContext context)
{
var Projects = new List<Project>
{
new Project {ProjectName="Just Spec It", ClientID = "GR Corp", Description="Build Just Spec It Application"}
};
Projects.ForEach(s => context.Projects.Add(s));
context.SaveChanges();
var UseCases = new List<UseCase>
{
new UseCase {ProjectID = 1, ActorID = 1, Title = "Print Specification"}
};
UseCases.ForEach(s => context.UseCases.Add(s));
context.SaveChanges();
var Steps = new List<Step>
{
new Step {UseCaseID = 1, Content = "This is step 1"},
new Step {UseCaseID = 1, Content = "This is step 2"},
new Step {UseCaseID = 1, Content = "This is step 3"},
};
Steps.ForEach(s => context.Steps.Add(s));
context.SaveChanges();
var Queries = new List<Query>
{
new Query {UseCaseID = 1, QueryDescription = "We need to add more details to this Use Case!"}
};
Queries.ForEach(s=> context.Queries.Add(s));
context.SaveChanges();
var Actors = new List<Actor>
{
new Actor {Title = "Business Analyst", Description = "This group will interact with the application to generate the use cases. They will follow Cockburn's writing process to produce the use cases in an effective way!"},
new Actor {Title = "End System User", Description = "These users will use the application for two primary purposes. The first is to submit uses case titles (which in fact will be their goals). After the Business Analyst has entered full details into the application about how these goals will be carried out, the End System Users will use the application again to review and comment on them."}
};
Actors.ForEach(s => context.Actors.Add(s));
context.SaveChanges();
}
}
}
JustSpecItInitialiser or JustSpecItInitializer ?
Check syntax.
I'm new at Telerik & exploring as an option for ORM. I'm trying to do simple thing like writing a record to database using:
Database db = Database.Get("MyConnectionNameIUsedToGenerateClasses");
IObjectScope scope = db.GetObjectScope();
scope.Transaction.Begin();
LookUpType l = new LookUpType();
l.IsActive = true;
l.Name = "test";
scope.Add(l);
scope.Transaction.Commit();
It throws following error: The connection section with id 'MyConnectionNameIUsedToGenerateClasses' cannot be found in the configuration files traversed from '(OpenAccess internally generated. Is there anything I'm missing from the setup? Telerik did add connectionString to my web.config file with it generated classes. Please help. Thanks.
OpenAccess ORM should know of all the assemblies used by the application. The assemblies should be listed under the reference section within the configuration file:
Open the web.config file in the web application project;
Locate the references node;
Alter the references node so that it gets the following form:
<references>
<reference assemblyname="AssemblyName" configrequired="True" />
</references>
The configuration file format is described here.
As I mentioned in the comments above following code works & does my job:
Telerik.OpenAccess.Data.Common.OAConnection dbConnection = dbContext.Connection;
LookUpType l = new LookUpType();
l.IsActive = true;
l.Name = "test123";
LookUpType lkup = new LookUpType();
lkup.IsActive = true;
lkup.Name = "someTest";
dbContext.Add(new LookUpType[] { l, lkup });
dbContext.SaveChanges();
I just don't know how to explain this clearly. So I create a simple image pattern of what I did.
My question is, how would I be able to access my database in other class in LS?
I've been searching on net, but I didn't found any solution. I hope I'll find it here.
Thanks!.
Any suggestion is already appreciated.
Thanks for the answer Bryan, but I found the answer on my problem here Richard Waddell
Here is what I did to achieve my goal.
Switch your LS project to file view
Go to "Common" project, under "UserCode" folder, create a class (e.g. Authenticate.cs) and put this codes.
The code follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.LightSwitch;
namespace LightSwitchApplication
{
public class Authenticate
{
public static adminuser GetCurrentUser()
{
adminuser userFound = (from useritem in
Application.Current.CreateDataWorkspace().basecampcoreData.adminusers
where useritem.LoginID == Application.Current.User.Name
select useritem).SingleOrDefault();
if (userFound != null)
return userFound;
else
return null;
}
}
}
Then you can now call the Authenticate.GetCurrentUser() anywhere in the project.
Thanks!
The main difference is the first set of code that works is running inside a screen. For your Authenticate class, you need to do the following steps to access the Database.
Note: I'm assuming that your datasource has the default name of ApplicationData since you hid the name, if not, make the corresponding changes. If it's a completely different datasource, change "_IntrinsicData" in the steps below)
These steps are taken from the Lightswitch Help Website
Navigate to ..ServerGenerated\GeneratedArtifacts (in the LightSwitch project) and click on ApplicationData.cs and Add As Link.
Add the following code below, this code dynamically creates a connection to the database. LightSwitch uses “_IntrinsicData” as it’s connection string.
private ApplicationDataObjectContext m_context;
public ApplicationDataObjectContext Context
{
get
{
if (this.m_context == null)
{
string connString =
System.Web.Configuration.WebConfigurationManager
.ConnectionStrings["_IntrinsicData"].ConnectionString;
EntityConnectionStringBuilder builder = new EntityConnectionStringBuilder();
builder.Metadata =
"res://*/ApplicationData.csdl|res://*/ApplicationData.ssdl|res://*/ApplicationData.msl";
builder.Provider =
"System.Data.SqlClient";
builder.ProviderConnectionString = connString;
this.m_context = new ApplicationDataObjectContext(builder.ConnectionString);
}
return this.m_context;
}
}
You should be able to access it through Context.adminusers