How to use DataProtectionKeys with multiple applications? - entity-framework

I'm running with the code below and I can see that one key is created in the table [DataProtectionKeys]
services.AddDataProtection()
.SetApplicationName(dataProtectionSettings.ApplicationName)
.ProtectKeysWithCertificate(serviceCertificate)
.UnprotectKeysWithAnyCertificate(serviceCertificate)
.PersistKeysToDbContext<DataProtectionContext>();
I'm using this database context (am I missing something?):
class DataProtectionContext : DbContext, IDataProtectionKeyContext
{
/// <summary>
/// A recommended constructor overload when using EF Core with dependency injection.
/// </summary>
/// <param name="options"></param>
public DataProtectionContext(DbContextOptions<DataProtectionContext> options)
: base(options) { }
/// <summary>
/// This maps to the table that stores keys.
/// </summary>
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
}
But, if I change to ApplicationName string value to something else, I don't see that a new key is created
Any idea why or how to fix it so this database table can support multiple application

Related

Identity with efcore for customer and staff

I currently design table for customer and staff for my ecommerce app and I am using asp.net core identity. I want to know if I should use 1 table user (aka aspnetuser) for staff and customer or should I separate them and use user id as foreign key? If separating them 2 new table with foreign key is user id, how can I use user manager for creating account for staff and customer?
Thanks.
You can extend the base IdentityUser class in order to create a table with additional fields, like:
public class MyIdentityUser : IdentityUser<string>
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Type { get; set; }
...
where the Type field could be Staff or Customer.
Or you can use one or more additional table and use the Id as defined in IdentityUser class from Microsoft.ASpNetCore.Identity:
public class IdentityUser<TKey> where TKey : IEquatable<TKey>
{
/// <summary>
/// Initializes a new instance of <see cref="IdentityUser{TKey}"/>.
/// </summary>
public IdentityUser() { }
/// <summary>
/// Initializes a new instance of <see cref="IdentityUser{TKey}"/>.
/// </summary>
/// <param name="userName">The user name.</param>
public IdentityUser(string userName) : this()
{
UserName = userName;
}
/// <summary>
/// Gets or sets the primary key for this user.
/// </summary>
[PersonalData]
public virtual TKey Id { get; set; }
...
you can define the type of your Id field, like my previous example, and use the same type on a related field (like IdentityUserId) in your custom table/tables.
If you extend the base IdentityUser class you need to create a derived context with this declaration, like this:
namespace MyProject.Infrastructure.Contexts
{
public class MyContext : IdentityDbContext<MyIdentityUser>
{
...

Global routing prefix in Core 3.1 API

I have attribute [Route("api/v{version:apiVersion}/[controller]")] on every controller and this is redundant.
Is there a way to set the api/v{version:apiVersion}/ part globally somewhere so I can just specify what the controller should be?
I've tried using a base controller, MapControllerRoute, and UsePathBase.
You should be able to create an attribute that implements IRouteTemplateProvider
/// <summary>
/// Class to ensure that we use our default naming convension for controller routes
/// </summary>
public class DefaultRoutingAttribute : Attribute, IRouteTemplateProvider {
public string Template => "api/v{version:apiVersion}/[controller]";
/// <summary>
/// Order is 2 to allow explicitly overriding the default route
/// </summary>
public int? Order => 2;
public string Name { get; set; }
}
and then use it like
[ApiController]
[DefaultRouting]
public class YourController : ControllerBase {}
I have not tested exactly your route with the apiversion but it works well with a simpler route in my application.

How to use windows workflow activity generated from cmdlet?

I generated WWF activity from cmdlet with PowerShell 3.0.
/// <summary>
/// Activity to invoke the Microsoft.Ceres.HostController.Cmdlets\Connect-Host command in a Workflow.
/// </summary>
[System.CodeDom.Compiler.GeneratedCode("Microsoft.PowerShell.Activities.ActivityGenerator.GenerateFromName", "3.0")]
public sealed class ConnectHost : PSRemotingActivity
{
/// <summary>
/// Gets the display name of the command invoked by this activity.
/// </summary>
public ConnectHost()
{
this.DisplayName = "Connect-Host";
}
/// <summary>
/// Gets the fully qualified name of the command invoked by this activity.
/// </summary>
public override string PSCommandName
{
get { return "Microsoft.Ceres.HostController.Cmdlets\\Connect-Host"; }
}
// Arguments
/// <summary>
/// Provides access to the Host parameter.
/// </summary>
[ParameterSpecificCategory]
[DefaultValue(null)]
public InArgument<System.String> Host { get; set; }
/// <summary>
/// Provides access to the Port parameter.
/// </summary>
[ParameterSpecificCategory]
[DefaultValue(null)]
public InArgument<System.String> Port { get; set; }
/// <summary>
/// Provides access to the NoConnectionSecurity parameter.
/// </summary>
[ParameterSpecificCategory]
[DefaultValue(null)]
public InArgument<System.Management.Automation.SwitchParameter> NoConnectionSecurity { get; set; }
/// <summary>
/// Provides access to the ServiceIdentity parameter.
/// </summary>
[ParameterSpecificCategory]
[DefaultValue(null)]
public InArgument<System.String> ServiceIdentity { get; set; }
// Module defining this command
// Optional custom code for this activity
/// <summary>
/// Returns a configured instance of System.Management.Automation.PowerShell, pre-populated with the command to run.
/// </summary>
/// <param name="context">The NativeActivityContext for the currently running activity.</param>
/// <returns>A populated instance of Sytem.Management.Automation.PowerShell</returns>
/// <remarks>The infrastructure takes responsibility for closing and disposing the PowerShell instance returned.</remarks>
protected override ActivityImplementationContext GetPowerShell(NativeActivityContext context)
{
System.Management.Automation.PowerShell invoker = global::System.Management.Automation.PowerShell.Create();
System.Management.Automation.PowerShell targetCommand = invoker.AddCommand(PSCommandName);
// Initialize the arguments
if (Host.Expression != null)
{
targetCommand.AddParameter("Host", Host.Get(context));
}
if (Port.Expression != null)
{
targetCommand.AddParameter("Port", Port.Get(context));
}
if (NoConnectionSecurity.Expression != null)
{
targetCommand.AddParameter("NoConnectionSecurity", NoConnectionSecurity.Get(context));
}
if (ServiceIdentity.Expression != null)
{
targetCommand.AddParameter("ServiceIdentity", ServiceIdentity.Get(context));
}
var cont = new ActivityImplementationContext() {PowerShellInstance = invoker};
return cont;
}
}
After I create activity1.xaml, put "Connect-Host" activity and write start code:
var workflow1 = new Activity1();
WorkflowInvoker.Invoke(workflow1);
but I receive exception with message:
"The type initializer for 'Microsoft.PowerShell.Workflow.ActivityHostProcess' threw an exception." "Could not find a part of the path 'C:\Windows\system32\windowspowershell\v1.0\modules\psworkflow\PSWorkflow.types.ps1xml'."
But this file exist in my system.
How I can use this technology?
This might be a problem with Windows Powershell.
The solution is to copy the folder: "PSWorkflow" from "C:\Windows\System32\WindowsPowerShell\v1.0\Modules\"
to "C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules"
Then everything works fine.

EF Code First Multilevel Inheritance Issue

I have an inheritance hierarchy setup that I am mapping to a DB via TPT in Code first. For the most part the hierarchy is one level deep, but sometimes it it two. My base class looks like this:
public class AuditEvent
{
public int AuditEventID;
//other stuff
};
Then I have a bunch of other classes that look like this (with different names and properties):
public class PageRequest : AuditEvent
{
/// <summary>
/// Page Request Id (Primary Key)
/// </summary>
public Int64 PageRequestID { get; set; }
/// <summary>
/// Screen (page) being requested
/// </summary>
public string Screen { get; set; }
/// <summary>
/// Http Method
/// </summary>
public string HttpMethod { get; set; }
/// <summary>
/// Confirmation Logs linked to this page request
/// </summary>
public virtual List<ConfirmationLog> ConfirmationLogs { get; set; }
}
This specific class (PageRequest) is a parent to one other class called ConfirmationLog, which looks like this:
/// <summary>
/// Object used to log confirmations to the auditing database
/// </summary>
public class ConfirmationLog : PageRequest
{
/// <summary>
/// Confirmation ID
/// </summary>
public long ConfirmationID { get; set; }
/// <summary>
/// Confirmation number
/// </summary>
public string ConfirmationNum { get; set; }
/// <summary>
/// Web action ID (automated alert or transaciton confirmation number)
/// </summary>
public int WebActionID { get; set; }
}
I'm configuring the mappings using configuration classes and the fluent API, like so:
/// <summary>
/// Configuration class for PageRequest
/// </summary>
public class PageRequestConfiguration : EntityTypeConfiguration<PageRequest>
{
/// <summary>
/// Default constructor
/// </summary>
public PageRequestConfiguration()
{
//Table
ToTable("PageRequests");
//primary key
HasKey(a => a.PageRequestID);
//Properties
Property(a => a.PageRequestID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(a => a.Screen).IsRequired().HasMaxLength(100);
Property(a => a.HttpMethod).IsRequired().HasMaxLength(10);
}
}
/// <summary>
/// Confirmation Log configuration class. Configures the confirmation log class for the db model
/// </summary>
public class ConfirmationLogConfiguration : EntityTypeConfiguration<ConfirmationLog>
{
/// <summary>
/// Default constructor
/// </summary>
public ConfirmationLogConfiguration()
{
//Map to Table
ToTable("ConfirmationLogs");
//Primary Key
HasKey(a => a.ConfirmationID);
//required fields
Property(a => a.ConfirmationID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(a => a.PageRequestID).IsRequired();
Property(a => a.ConfirmationNum).IsRequired().HasMaxLength(12);
Property(a => a.WebActionID).IsRequired();
}
}
I then create a rather large LINQ query based on this hierarchy. I'll spare that query because it's composed in about 10 steps, and I don't think that's the source of my problem. The problem is, when I run the query, the SQL generated for some reason thinks that the column AuditEventID (the primary key for the base class), exists on the ConfirmationLogs table (the grandchild table). The ConfirmationLogs table has a foreign key to it's parent table (PageRequests), which then has the foreign key to it's parent table (AuditEvents).
My question is, did I set this hierarchy up wrong? Does the "grandchild" table need the foreign key to both it's parent and grandparent for this to function? (if it does I find that unfortunate).
I'm positive that the inheritance relationship is throwing things off because if I don't make ConfirmationLogs a child of PageRequests and configure the relationship to PageRequests with HasRequired()/WithMany(), things work fine.
Any help would be appreciated.
Update
So, after further investigation I think there is a general problem with the way I'm trying to use inheritance. I should note that I'm trying to map code first to an existing database. In the database, I have my AuditEvent table, and a bunch of "child" tables like PageRequest. Page request has it's own primary key called PageRequestID, as well as a foreign key called AuditEventID. The other child tables are setup the same way. In my Configuration class for PageRequest (listed above), I'm trying to map this by using the HasKey function to say that the PageRequestID is the primary key, and assuming that EF will know about the foreign key AuditEventID by convention and inheritance. I should also note that I can write to the DB using the model just fine. If I want to write a PageRequest, I create PageRequest object, populate all the required fields as defined by both the PageRequest and AuditEvent base class, and save through the context. EF creates the AuditEvent record, and the pageRequest record with the FK back to AuditEvent.
What makes me think I'm not using inheritance right is that I allowed EF to create my database for me, using the model and mapping I've created. For the PageRequest table (and all other child tables), EF actually created a primary key called AuditEventID (even though my configuration is telling it to do otherwise). This key is also labeled as a foreign key, and the column that I want to create as a primary key (PageRequestID in this example) is just configured as being required (non-nullable). So it appears that EF taking the primary key from my BASE class and using that as a primary key AND foreign key in my child classes, almost like the concept of the AuditEventID is spread between the parent and child tables. Is there a way to change this behavior?
You are saying this didn't work, and it still expected an AuditRequestID in the table that had the ConfirmationLog object? I'm looking at the reference: Specifying Not to Map a CLR Property to a Column in the Database in http://msdn.microsoft.com/en-us/data/jj591617#1.6
public ConfirmationLogConfiguration()
{
//Map to Table
ToTable("ConfirmationLogs");
//Primary Key
HasKey(a => a.ConfirmationID);
//required fields
Property(a => a.ConfirmationID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
Property(a => a.PageRequestID).IsRequired();
Property(a => a.ConfirmationNum).IsRequired().HasMaxLength(12);
Property(a => a.WebActionID).IsRequired();
Ignore(a => a.AuditEventID);
}
Good luck.

How to refresh data in Entity Framework 4.1 code first

I have the following context:
public class DataContext : DbContext
{
/// <summary>
/// Gets or sets Addresses.
/// </summary>
public DbSet<Address> Addresses { get; set; }
/// <summary>
/// Gets or sets Users.
/// </summary>
public DbSet<Users> Users { get; set; }
}
I my application user may change data in say user data and then he may want to cancel changes. The best way to do this, is to refresh the DataContext from the database. But DbContext has no Refresh method. How can I refresh my DataContext?
You can reload the entity from the database as follows.
context.Entry(user).Reload();
Or you can try out the methods described in this question.