How to use enum in AuthorizeAttribute the razor mvc? - c#

I have this enum:
public enum PerfilUsuarioEnum
{
AdministradorSistema = 1,
AdministradorLoja = 2,
Gerente = 3
}
And I want to pass it on my Authorize roles
[Authorize(Roles = PerfilUsuarioEnum.AdministradorLoja + ", " + PerfilUsuarioEnum.Gerente)]
There is some manner to do this?

Roles has to be constant expression such as string. Easiest way is to use cosntant.
public static class PerfilUsuario
{
public const string AdministradorLoja = "AdministradorLoja";
public const string Gerente = "NaviGerentegators";
}
[Authorize(Roles = PerfilUsuario.AdministradorLoja + ", " +
PerfilUsuario.Gerente)]

Great question. Here is what I did...
I decided to make my permissions database driven so I needed a way to convert strings into something "typed" so that I could get compile time warnings and also so I could change the name of the permission in the database and not have to update all of our production code. Since the attributes are string based (so called magic strings), I decided against enumerations and went with a T4 script that read the database and generated a struct for each record. This allowed me to also add things like, a nice display name, details about the permission, and an error message that I could show the user.
Here is a sample permission row after the T4 template runs.
public struct CanViewClaimData
{
// Using const allows the compiler to generate the values in the assembly at compile time and satisfy MVC Authorize Attribute requirements for const strings.
public const System.String Name = "CanViewClaimData";
public const System.String DisplayName = "Can View Claim Data";
public const System.String Description = "The allows users to view claim data";
public const System.String DefaultErrorMessage = "You must have the \"Can View Claim Data\" permission to access this feature.";
}
Then in code I use a sub classed Authorize and mark the Action as such,
[Security.AuthorizedAttribute(Roles = CanViewClaimData.Name, Message = CanViewClaimData.DefaultErrorMessage)]
Then during each automated build and push to our C.I. environment, I run the T4 template as part of the build process to keep the struct strings in sync with the database.
So far this has worked really well and allowed me to give our product owner the ability to edit the permission names, descriptions etc, in the database and without a developer having to be involved.

Related

Entity Framework connection string from .DSN file

I have a problem, so I thought I would come to the brightest minds on the web.
I have written an ASP.NET MVC application that interfaces with a web service provided by another application. My app basically just adds some features to the other web application.
Both applications have a database. I am trying to limit the configuration for my application by using the other applications SQL Server credentials. This is so that if they decide to change the password for the other application, mine will just start working.
These credentials are saved in a .DSN file that my application can reach. How can I get my application, which uses Entity Framework, to use a connection string that is created from the details read in the .DSN file?
I can figure out the code to read the .DSN file, so if you wish to provide some code examples you can base them around setting the connection string for EF.
I am also open to other solutions, or even reasons why I shouldn't do this.
Thanks in advance.
PS. As I was writing this, I came up with a little concept. I am going to test it out now to see how it goes. But here is the basics:
On start up, read the needed details into static properties.
public MyContext() : base(getConnectionString()) { }
3.
private SomeObjectTypeHere getConnectionString()
{
//read static properties
//return .....something..... not sure yet....
}
Thoughts on that maybe?
EDIT
I have created a method that reads the .DSN file and gets the server, the user id and the password. I now have these stored in static properties. In my context, how can I set my connection string now that i have the required details.
So, the biggest issue that I was really having was how to set my connection string in Entity Framework. But I was also hoping that maybe someone else had worked with .DSN files.
Anyway, here was my solution. Still looking for problems that might arise from this, so if you can see any issues, let me know!
First, I created a method that was run on startup. This method ran through the .DSN file and picked out the gems.
Keep in mind that I have never worked with .DSN files, and the section that gets the password is unique to my situation.
var DSNFileContents = File.ReadAllLines(WebConfigurationManager.AppSettings["AppPath"] + #"\App.DSN");//reads DSN into a string array
//get UID
string uid = DSNFileContents.Where(line => line.StartsWith("UID")).First().Substring(4);//get UID from array
//test if uid has quotes around it
if (uid[0] == '"' && uid[uid.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
uid = uid.Substring(1, uid.Length - 2);
}
//get server
string server = DSNFileContents.Where(line => line.StartsWith("SERVER")).First().Substring(7);//get the server from the array
//test if server has quotes around it
if (server[0] == '"' && server[server.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
server = server.Substring(1, server.Length - 2);
}
//THIS WON'T WORK 100% FOR ANYONE ELSE. WILL NEED TO BE ADAPTED
//test if PWD is encoded
string password = "";
if (DSNFileContents.Where(line => line.StartsWith("PWD")).First().StartsWith("PWD=/Crypto:"))
{
string secretkey = "<secret>";
string IV = "<alsoSecret>";
byte[] encoded = Convert.FromBase64String(DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(12));
//THIS LINE IN PARTICULAR WILL NOT WORK AS DecodeSQLPassword is a private method I wrote to break the other applications encryption
password = DecodeSQLPassword(encoded, secretkey, IV);
}
else
{
//password was not encrypted
password = DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(4);
}
//build connection string
SqlConnectionStringBuilder cString = new SqlConnectionStringBuilder();
cString.UserID = uid;
cString.Password = password;
cString.InitialCatalog = "mydatabase";
cString.DataSource = server;
cString.ConnectTimeout = 30;
//statProps is a static class that I have created to hold some variables that are used globally so that I don't have to I/O too much.
statProps.ConnectionString = cString.ConnectionString;
Now that I have the connection string saved, I just have my database Context use it as below,
public class myContext : DbContext
{
public myContext() : base(statProps.ConnectionString) { }
//all my DbSets e.g.
public DbSet<Person> Persons{ get; set; }
}
This is simple, yes, but I hoping that it can provide some information to anyone that was looking to do something similar but was not sure about how it should be handled.
Again, let me know if you like or dislike this solution and if you dislike it, what is your solution and why.
Thanks again!

C# class property getting cached?

I have a class and am setting a UID as a class property because it is used in many methods throughout the program and I don't want to keep having to pass in a value to it. The issue I'm getting is that when I run context.Response.Write(uid) and refresh the page, I get the same value every time.
If I move createRandomString() to context.Response.Write(createRandomString()), I get a new UID every time I reload.
I'm very new to using C# and coming from a PHP background, this is a bit odd for me. I would think that setting a class property would change every load. I'm thinking it probably has something to do with when the program is compiled, the UID is permanently set which still wouldn't make sense.
Code where property is getting set:
public class Emailer : IHttpHandler {
// Define UID
static string uid = createRandomString();
CreateRandomString Code:
public static string createRandomString() {
Guid g = Guid.NewGuid();
string GuidString = Convert.ToBase64String(g.ToByteArray());
GuidString = GuidString.Replace("=", "");
GuidString = GuidString.Replace("+", "");
return GuidString;
}
Static fields are only instansiated once. That is why you always get the same result. Try this...
public class Emailer : IHttpHandler
{
// Define UID
string uid => createRandomString();
}
https://msdn.microsoft.com/en-us/library/aa645751(v=vs.71).aspx
Static class level members with an initialiser are only once the first time any memeber of the class (static or otherwise) is referenced.
The initialisation will only re-run when the assembly the class is contained in is unloaded from memory (e.g. when then executable is unloaded).
For an ASP application the assemblies are loaded and unloaded by the IIS process so you would fund that if you restarted the IIS process (for example) this would cause a new UID to be generated.
Solved it by keeping the fields static but setting the value upon load.
Fields:
// Define UID
static string uid = "";
// Define upload path for files
static string uploadPath = "";
Setting:
// Define UID
uid = createRandomString();
uploadPath = #"c:\" + uid + #"\";

Replace an xml names with a variable

I am working on SharePoint. I have two sites one main site and a sandbox. Their codes are same but xml names of columns are different. So I am trying to make a code in such a all xml names will be replaced by their variables.plzz check my code below.
#if TestSite
public const string context = "url";
public const string Title = "xmlname1";
public const string User_id = "xmlname2";
#else
public const string context = "url2";
public const string Title = "xmlname1";
public const string User_id = "xmlname2";
#endif
when I debug this program it connects to url1....how will I connect it to url2?
Both urls should work for Common code.
It is better to put some kind of identifier in the settings of your program. Then the user can set whether to connect to site A or B.
Sometimes you can use the URL to determine to which system you are connecting, or maybe you can even get the metadata from the service itself, removing the need to keep record of the column names to get. Then you first fetch the metadata, and then actually make the calls to the data endpoints.

NRefactory: How do I access unresolved Named Arguments on a Property Attribute?

I apologize in advance for the long description of a simple question but I want to make sure people properly understand what I'm trying to do.
Background
I'm writing a tool that can read in a file generated by SqlMetal and create a class that contains methods for simple Inserting, Updating, Deleting and Selecting, which can then be exposed to a web service. The main advantage here is that if a table changes, I simply have to re-run the tool and the database-related code is automatically updated and everywhere that uses it will generate compile errors, making it easy to track down where manual changes need to be made. For example, if I have a Customer table that has the following fields:
CustomerId (PK, Identity)
FirstName
LastName
I want to be able to generate Insert and Delete methods as follows:
// I only want non-database-generated fields to be parameters here.
public static Customer InsertCustomer(String firstName, String lastName)
{
...
}
// I only want the primary key fields to be parameters here.
public static int DeleteCustomer(int customerId)
{
...
}
I am using SqlMetal to generate a Customer class. Now what I want to do is read that .cs file into my new tool in order to create another class with the above methods. This new class can then be exposed to the web service to grant access to this functionality without having to expose the underlying database. I am using NRefactory to read in the SqlMetal-generated file and so far, it's going well but I've run into a snag trying to read the property attributes on my Customer class.
SqlMetal generates its classes using a ColumnAttribute to identify each property that is derived from a database column. The ColumnAttribute will have a number of arguments to describe the database column's properties. In the above example, it would generate something like this:
...
[Column(Name="customerId", Storage="_CustomerId, DbType="INT NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)]
public int CustomerId
{
...
}
[Column(Name="firstName", Storage="_FirstName", DbType="NVarChar(100) NOT NULL", CanBeNull=false)]
public String FirstName
{
...
}
[Column(Name="lastName", Storage="_LastName", DbType="NVarChar(100) NOT NULL", CanBeNull=false)]
public String LastName
{
...
}
...
Problem
As you can see, SqlMetal gives me the attributes I need in order to identify which columns are database-generated and which ones are part of the primary key. So when I read this file into NRefactory and resolve the type, I would expect to be able to get at all of this information. However, I'm finding that while I can get to the ColumnAttribute, all of the arguments on it are unresolved and therefore aren't accessible via the NamedArguments or PositionalArguments properties.
Here's my code:
SyntaxTree syntaxTree = ...;
foreach(AstNode tableNode in syntaxTree.Children)
{
ResolveResult result = resolver.Resolve(tableNode);
var properties = result.Type.GetProperties();
foreach (IProperty p in properties)
{
var attributes = p.Attributes;
bool isPrimaryKeyField = false;
bool isDbGenerated = false;
bool isColumn = false;
foreach (IAttribute attr in attributes)
{
if (attr.AttributeType.Name == "Column")
{
isColumn = true;
foreach (var arg in attr.NamedArguments) // NamedArguments contains no items.
{
if (arg.Key.Name == "IsPrimaryKey")
{
isPrimaryKeyField = (bool)arg.Value.ConstantValue == true;
}
if (arg.Key.Name == "IsDbGenerated")
{
isDbGenerated = (bool)arg.Value.ConstantValue == true;
}
}
}
}
if (isColumn)
{
... // Create a parameter as appropriate.
}
}
}
This all works until I try to loop through the IAttribute.NamedArguments because the collection contains no elements. However, when I go through the debugger and examine the value of 'attr', I can see that there is a private variable called 'unresolved', which contains a list of all the arguments I want but I can find no way to access this through code.
How do I get at the contents of this 'unresolved' variable? Do I need to do something more with the Resolver? This is my first time using NRefactory so I'm not overly familiar with all the nuances yet. I've been having a tough time finding an example that goes into this level of depth on Google and the documentation I've seen for NRefactory doesn't seem to cover it. Any help would be appreciated.
I figured it out. I needed to load the assembly for System.Data.Linq into the IProjectContent before resolving the SyntaxTree.
...
CecilLoader loader = new CecilLoader();
Assembly[] assembliesToLoad = {
...
typeof(System.Data.Linq.Mapping.ColumnAttribute).Assembly
...};
IUnresolvedAssembly[] projectAssemblies = new IUnresolvedAssembly[assembliesToLoad.Length];
for(int i = 0; i < assembliesToLoad.Length; i++)
{
projectAssemblies[i] = loader.LoadAssemblyFile(assembliesToLoad[i].Location);
}
IProjectContent project = new CSharpProjectContent();
project = project.AddAssemblyReferences(projectAssemblies);
...

Changing ResourceManager (Make it Updatable)

I have a project in MVC 3 (Razor) For localization we are using Strongly typed resources.
We want to have possibility to update translation that already exist "on-line". It means, that it should be possible to edit translation on the website. (e.g. If in the url there is parameter like "translateLanguage=on") Basically, it is not possible to do that with current solution, because if resource has been changed, then it must be recompiled.
Of course we can write our own Resource Manager that will be using a database, but then we would have to rewrite all of our translations to the database and that would be time consuming. It would also mean that we would have to change all of our code to reflect this "new" resource manager.
It would be hard to implement it in all things. Now, we can use it in attributes
e.g.
[Required(ErrorMessageResourceType = typeof(_SomeResource), ErrorMessageResourceName = "SomeResouceElement")
SomeProperty
As well as in code:
string translatedResource = _SomeResource.SomeResourceElement;
Could you provide me with some information how to do this in mvc 3?
Generally resource file consists of two parts xml + autogenerated cs code. If you open resource designer file you will see
/// <summary>
/// Looks up a localized string similar to About project.
/// </summary>
public static string about_project {
get {
return ResourceManager.GetString("about_project", resourceCulture);
}
}
So what you can do you can use ResourceManager.GetString("Key")
Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureName);
var t = Resources.ResourceManager.GetResourceSet(new CultureInfo(cultureName), true, true);
To make it more smart you can rewrite BaseView
public abstract class ViewBase<TModel> : System.Web.Mvc.WebViewPage<TModel>
{
public string GetTranslation(string key)
{
return _rManager.GetString(key);
}
private ResourceManager _rManager;
protected ViewBase()
{
_rManager = Resources.ResourceManager.GetResourceSet(new CultureInfo(cultureName), true, true);
}
}
And then you will be able to use GetTranslation in your razor view (To run this base view you need to modify web.config from Views folder)
And then you will be able after editing xml access to resource data.

Categories