MVC Asp.NET Identity Unknown Error Occurring - asp.net-mvc

I'm working on an MVC site that is using ASP.Net Identity for the log in piece.
There is a user table where the pk is an FK for another table (table 2). Because of this, the user cannot be deleted. As well, there are reports that are generated from table 2. This report displays the data from table 2 as long as the user name that generated the data. Another reason why deleting the user information should not be done.
So instead of deleting the user I thought I would add a column to the user table called "Deleted". It uses a bit datatype.
The column was added to my local copy of the database using code-first migrations. When the user logs on, this value is checked in this column is checked (0 = not deleted; 1 = deleted).
Everything was working great on my local machine. I had no errors, code ran fine. I was able to log in with any user. I then deployed to our test server and added the "Deleted" column to the table on the test SQL server using a script.
When I went to log in, with any user, I couldn't. I kept getting the "Error logging in. Please re-enter credentials and try again" even though my credentials were correct.
I deleted the files on the server and deployed again. Same thing.
I backed out all of my changes and deployed again and was able to log in.
So, I started adding things a piece at a time:
I ran the script to add a Deleted column with a bit datatype and set
to not null on our test SQL server
Tested logging in and was able to
Added public bool Deleted {get; set;} to my BL Entity and deployed to
test
Tried logging in and failed
Removed the Deleted bool and re-deployed
Was able to log in
I'm not understanding why this addition is causing issues. "Deleted" columns are used in other tables in the application and have not caused any issues. And because it's working fine when I run it locally I'm having a hard time determining what the issue is.
Here is my BL Entity:
using Microsoft.AspNet.Identity.EntityFramework;
using System;
using System.Collections.Generic;
namespace BlahBlah.BusinessLogic.Entities
{
public class User : IdentityUser
{
public User() : base() { }
public User(string username) : base(username) { }
public Guid CompanyId { get; set; }
public Company Company { get; set; }
public bool PrimaryAccount { get; set; }
public Guid DefaultCompanyId { get; set; }
public ICollection<Transaction> Transactions { get; set; }
// public bool Deleted { get; set; }
}
}
Here is a piece of my user.js code:
...
$http(call)
.success(function (data) {
userData.isAuthenticated = true;
userData.username = data.userName;
userData.role = data.role;
userData.bearerToken = data.access_token;
userData.expirationDate = new Date(data['.expires']);
setHttpAuthHeader();
if (typeof successCallback === 'function') {
successCallback();
}
})
.error(function (data) {
if (typeof errorCallback === 'function') {
if (data.error_description) {
errorCallback(data.error_description);
}
else {
errorCallback('Unable to contact server; please, try again later.');
}
}
});
};
...
Here is a piece of my login.js code:
...
function login(common, $location, config) {
var getLogFn = common.logger.getLogFn;
var log = getLogFn(controllerId);
var vm = this;
vm.title = 'Login';
vm.credentials = {
username: '',
password: ''
};
vm.hideError = true;
vm.errorMessage = 'xx.';
vm.login = function login() {
vm.hideError = true;
common.$broadcast(config.events.spinnerToggle, { show: true });
common.user.authenticate(vm.credentials.username, vm.credentials.password, onSuccessfullLogin, onFailedLogin);
};
...
function onFailedLogin(error) {
common.$broadcast(config.events.spinnerToggle, { show: false });
console.log('error ' + error);
vm.hideError = false;
}
...
Any ideas as to what is going on or how I can find out what is going on? Thanks for your time!
UPDATE
I shouldn't have gotten too excited. After performing some testing in the application I thought I would test the reports. Everything was working beautifully up until then. When I viewed a report I got the following error:
The model backing the 'BabDbContext' context has changed since the database was created. Consider using Code First Migrations to update the database
The reports are using SSRS. If I ran the script to create the column AND update the _Migrations table I'm not understanding why I'm getting this error. The stack trace points to the last line. I've read suggestions but where I need to add some code to the OnModelCreating method but I'm not sure if that's the way to go. There have been other deploys done by others prior to me so I'm missing something.
public class AbaDbContext : IdentityDbContext<User>, IDbContext
{
public const int UnknownCTId = 1;
private IEncryptionService _encryptionService;
private static Dictionary<Guid, string> _cipherCache = new Dictionary<Guid,string>();
public BabDbContext()
: base("BabDbContext")
{
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += new ObjectMaterializedEventHandler(ObjectMaterialized);

It looks like your context is trying to run migrations on the production server and is failing due to either insufficient permissions or that the Deleted column already exists. Your options are:
Run your production migrations by creating a script. You can do this by running the following command:
Update-Database -Script
This will create a SQL script that yuo can run against your database to create the column and, critically, insert a row into the __MigrationHistory table that tells EF that it doesn't need to run migrations again.
Create a context initialiser that effectively disables migrations. Add a class that inherits from NullDatabaseInitializer<T>:
public class DisableMigrations : NullDatabaseInitializer<YourContext>
{
}
And in your production web.config:
<entityFramework>
<contexts>
<context type="YourNamespace.Domain.YourContext, YourNamespace.Domain">
<databaseInitializer
type="YourNamespace.Domain.DisableMigrations, YourNamespace.Domain"/>
</context>
</contexts>
</entityFramework>

Related

Model backing the Db context has changed but run anyway. Is there a way to turn off migrations?

I want my windows application to warn that there are migrations to run but to give the user the option to continue without running them.
At the moment I have code first projects with no migrations that access the database
However in the project where I do the database migrations I must either allow the migration to run or delete the migration and undo my changes to the model.
For the configuration I have
internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
For the migration check I have
using (var db = new MyDbContext())
{
var compatible = db.Database.CompatibleWithModel(false);
if (!compatible)
{
compatible= RunMigrations(db);
}
return compatible;
}
If I don't allow the migration then I get the model backing error when I try to access data
var n = db.mytable.count() // will error
If I comment out the Configuration class and code that calls it I can run the program without error.
The trick is to create a new dbContext inheriting from the usual
public class MigrationDbContext : MyDbContext
{
}
Then the configuration class should use the MigrationDContext
internal sealed class Configuration : DbMigrationsConfiguration<MigrationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
and the migration check should use the MigrationDbContext

MVC download of clickonce Setup.exe and display confirmation view

I'll start by saying i'm a C# MVC newbie, but I've set up a site with Identity Management and extended the database with some custom tables to store additional info about my users, so I'm not a total neophyte. I've been working on a VB WPF application that I want to deploy from my new website and that is where I'm running into an issue.
I've created a new controller (User) and a couple of views (Download) & (Setup). I created a downloadmodel used by the download view.
In abstract what I am doing is displaying the download view (get) which has three checkboxes to confirm the user has read the Overview, Installation, and Terms of Service. These are boolean values in the model. I also have a string response message in the model, that displays just above the submit button. Here is the model:
public class DownloadModel
{
public bool Overview { get; set; }
public bool Installation { get; set; }
public bool TermsOfService { get; set; }
public string Response { get; set; }
public DownloadModel()
{
Overview = false;
Installation = false;
TermsOfService = false;
Response = "After checking boxes click the button to begin installation";
}
}
My User Controller handles the Get to initially display the download view, and then in the Post it checks to see if all the checkboxes were ticked, if not it updates the response message and returns the view.
If the checkboxes are all checked then it pulls the subscriber (which must exist because it was created when the user verified their e-mail via the account controller - identity management), then proceeds to update the subscriber with the original (if new) or last download date(s). At this point I want to begin downloading the clickonce setup.exe file, before returning the setup view.
[Authorize]
public class UserController : Controller
{
// GET: User/Download
public ActionResult Download()
{
return View(new DownloadModel { });
}
// Post: User/Download
[HttpPost]
public ActionResult Download(DownloadModel downloadcheck)
{
if (!ModelState.IsValid)
{
return View(downloadcheck);
}
//check to see if all the boxes were checked
if (downloadcheck.Overview == true &
downloadcheck.Installation == true &
downloadcheck.TermsOfService == true)
{
//yes - so let's proceed
//first step is to get the subscriber
Subscriber tSubscriber = new Subscriber();
tSubscriber.Email = User.Identity.Name;
bool okLoad = tSubscriber.LoadByEmail();
if (okLoad == false)
{
//we have a real problem. a user has logged in but they are not yet
//a valid subscriber?
throw new Exception("Subscriber not found");
}
// update subscriber with download in process...
if (tSubscriber.OriginalDownload == DateTime.MinValue)
{
tSubscriber.OriginalDownload = DateTime.Now;
tSubscriber.LastDownload = tSubscriber.OriginalDownload;
}
else
{
tSubscriber.LastDownload = DateTime.Now;
}
if (tSubscriber.UpdateDownloaded() == false)
{
//update of download dates failed
//another problem that shouldnt occur.
downloadcheck.Response = "A problem occured downloading your setup."
+ "Try again. If this error continues please contact support.";
return View(downloadcheck);
}
//download dates have been updated for the subscriber so let's start the download!
//THIS IS WHERE I NEED TO BEGIN THE DOWNLOAD
return View("Setup");
}
else
{
// all boxes were not checked - update message
downloadcheck.Response = "Please confirm you have reviewed the above information "
+ "by checking all of the boxes before clicking on the button.";
return View(downloadcheck);
}
}
}
The download view is pretty straight forward, and the setup view simply confirms the download was started and provides a link to the help-setup page.
I'm really a bit lost here. I thought I'd plug in a return new filepathresponse, but I can't do that and return the setup view.
My other thought was to somehow trigger the download of my /xxx/setup.exe from within the setup view as it is returned - but I'm at a loss as to how to accomplish this.
I'll be the first to admit that my mvc c# code is probably overly verbose and my approach to how I've done this may be totally wrong, but I'm just scrambling to get this done so I can deploy my WPF app to select Beta users for testing. It's been a long time living off savings and I can smell go-live from here.
One final note, I'm using setup.exe clickonce deployment of my wpf app for simplicity, as there are .net and localsqldb prerequisites, but I will not be using automated updates - not that this is really relevant.
Appreciate all input and advice.
After more digging and hacking I've found a solution that works. Firstly in my setup view (confirmation page) I added a simple script to initiate a new function in my user controller:
<script type="text/javascript">
window.location.href = "/user/sendfile/"
</script>
The controller change was simple too. For testing I just used a txt file.
// User/SendFile
public ActionResult SendFile()
{
string path = #"~/xxxx/anyfile.txt";
string content = "application/txt";
//string content = "application/x-ms-application";
return new FilePathResult(path, content)
{
FileDownloadName = "mynewtext.txt"
};
}
What is really interesting about this solution is that the FileDownloadName is what the file content is downloaded as. So in this way I can refer to the actual setup.exe file in the path, but then name the downloaded exe anything I want. Bonus :)

Object reference not set to an instance of an object in umbraco 4.8.1

Due to performance issue , I have added the publishing code in thread.
My code is:
public void functionname()
{
----------------
------------
try
{
HttpontextforMailSending gethttpcontextforpublish2 = new HttpontextforMailSending()
{
HttpContextReference = HttpContext.Current,
courseDocument = shortCourseDocument,
createdUser = new User(0)
};
Thread t2 = new Thread(PublishDocument);
t2.Start(gethttpcontextforpublish2);
}
catch { }
-------------
-----------
}
private void PublishDocument(object input)
{
HttpontextforMailSending httpcontextformail = (HttpontextforMailSending)input;
Document course = httpcontextformail.courseDocument;
User createduser = httpcontextformail.createdUser;
if (course != null && createduser != null)
{
course.Publish(createduser);
umbraco.library.UpdateDocumentCache(course.Id);
}
}
public class HttpontextforMailSending
{
public HttpContext HttpContextReference { get; set; }
public Document courseDocument { get; set; }
public User createdUser { get; set; }
}
But I get Object reference not set to an instance of an object" error on "course.Publish(createduser);
The Umbraco version is 4.8.1.
May be this error is due to course.HttpContext. It has null value.
However when I set it as course.HttpContext = httpcontextformail.HttpContextReference; it shows a warning
"umbraco.cms.businesslogic.web.document.HttpContext is obsolete. Do not use this. GethttpContextvia regular ASP.Net methods instead.
When I debug this code, I get HttpContext on httpcontextformail.HttpContextReference.
But after executing course.HttpContext = httpcontextformail.HttpContextReference;, course.HttpContext still have null value.
Please help me
Thanks
Umbraco expects to be used within a web request and therefore the API will not work if called outside of a web request in another application etc.
If you want to execute some something using the Umbraco API externally then you will need to use Umbraco Base (or similar) so that the API has the needed HttpContext.
Umbraco Base is a RESTlike system for allowing the execution of queries or code via defined URLs within an Umbraco context.

Creating history table using Entity Framework 4.1

I am working on asp.net MVC 3 application and I am using codeFirst approach. I am trying to create history table or user table, Where I want to keep track of what columns were modified by user. How can I do this using EF Code First.
Do I need to do it after DataContext.savechanges ?
Please suggest.
Thanks.
The DbContext has a method called Entry<T>:
var entity = context.Items.Find(id);
entity.Name = "foobar";
var entry = context.Entry<Item>(entity);
entry will be of type DbEntityEntry<T> and has the properties OriginalValues and CurrentValues.
You could probably write something that will generically inspect these properties to see what has changed and then automatically insert a new record into your history table.
Either that, or use database triggers.
I'm not sure if this is really the "appropiate" way to do it, but this is how its usually done in sql:
Create an extra property version of type int or something.
Because you probably do not want to loop every time, add another property IsLatestVersion of type bool
When an entity is saved, check if the entity already exists. If so, set the entity on IsLatestVersion = false.
Increment the version, and save the changes as new entity.
Sounds to me like you want an a filter that inherits from ActionFilterAttribute. In my case, this is the simplest example that I have. This is my model, notice that the attributes dictate the mapping to the database.
[Table("UserProfile")]
public class UserProfile
{
[Key, DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
In my case, it was as simple as the following, although it was not historical:
public sealed class UsersContext : DbContext
{
public UsersContext() : base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
LazyInitializer.EnsureInitialized(ref _initializer, ref isInitialized, ref initializerLock);
}
public void CheckDatabase()
{
Database.SetInitializer<YourDBContextType>(null);
using (var context = new YourDBContextType())
{
if (!context.Database.Exists())
{
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
// Uses your connection string to build the following table.
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
The end result is not only EF being code first, but also allows for your models for your views to use primitives derived from your complex entities. Now, if you have another, lets say historical, DBContext then I would recommend modifying either the text transformation file or creating a base class for your entities. Both ways allow for an easy generation of code that could insert into your table, then follow up with that entity, clone it into a historical model and save. All that being said, I am a fan of database first approaches with concentration on constraints, triggers, etc. instead of a framework.

How do I specify multiple keys in DataServiceKey attribute for WCF Data Service data context object

I am using Reflection provider for my WCF Data Service and my Data Context object has two key members, say EmpId and DeptId.
If I specify [DataServiceKey("EmpId", "DeptId")], the service doesn't work. When I try to access the collection with the URL http://localhost:55389/DataService.svc/EmployeeData, I get the following error:
The XML page cannot be displayed
Cannot view XML input using XSL style
sheet. Please correct the error and
then click the Refresh button, or try
again later. The following tags were
not closed: feed. Error processing
resource
'http://localhost:55389/DataService.svc/EmployeeData'.
With single member in the DataServiceKey, it works fine. I tried with Custom Data Provider and I could achieve this functionality. But if I can do it with the Reflection provider, that would be great.
I don't think the problem is the multiple keys. To confirm please use for example Fiddler or something similar to grab the whole response from the server and share the error in it (as I'm sure there will be one in there).
Guessing from the description I think the problem is that one of your key property values is null. That is not supported and would cause so called in-stream error which would leave the response XML incomplete (which seems to be your case).
OData can handle multiple keys but all keys must have a valid value. Review this for OData's rule. If you want to retrieve an entry with EmpId=1 and DeptId=someString, you should reconstruct your URI into something like:
http://localhost:55389/DataService.svc/EmployeeData(EmpId=1,DeptId='someString')
Be careful in OData queries because they are case sensitive.
That is weird, I just tried this:
public class Context
{
public IQueryable<Person> People {
get {
return (new List<Person> {
new Person { EmpId = 1, DeptId = 2, Name = "Dude" }
}).AsQueryable();
}
}
}
[DataServiceKey("EmpId", "DeptId")]
public class Person
{
public int EmpId { get; set; }
public int DeptId { get; set; }
public string Name { get; set; }
}
public class WcfDataService1 : DataService<Context>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
}
}
And it works just fine, do you notice any major differences?
-Alex

Resources