Lesson 1 – Assemblies and Resources
Assemblies
-
project that compiles to .EXE or .DLL
-
primary deployment unit
-
collection of types and resources bound into logical unit of functionality
-
self describing – contain all info runtime requires to interpret contents and
configure itself for execution
-
.EXE and .DLL resemble predecessors externally
-
Different internal structure of four parts
-
Manifest (or metadata) contains info that runtime and CLR extract
-
Type metadata details types contained in assembly
-
Intermediate language for assembly
-
Resource files
-
Manifest contains
-
Identity – name and version number
-
Types and resources – list of types exposed to CLR as well as info about how
types can be accessed
-
Files – list of files in assembly and dependency info for those files
-
Security permissions – permissions required by assembly, if conflict with local
security permission then assembly fails to execute
-
Manifest created automatically, developer must set identity information
themselves
-
Identity info contained in AssemblyInfo.cs – can set by right clicking
AssemblyInfo icon and choosing View Code
[assembly:
AssemblyTitle(“”)]
[assembly:
AssemblyDescription(“”)]
[assembly:
AssemblyConfiguration(“”)]
…
Class Library Assemblies
-
Represent sets of types that can be referenced and used in other assemblies
-
Not executable, referenced by executable apps
-
Create using templates provided by .NET
-
From File menu choose New, then Project
-
Select C# Projects and then Class Library or Windows Control Library
-
Write code
-
Set required identity information
-
Build assembly
Resources and Resource Assemblies
-
.NET includes sample app called ResEditor for creating Text and Image resources
-
must be compiled prior to use
-
specify type and name of resources
-
supply values (strings or images)
-
save as .resources binary file or .resx XML file
-
Embeding resources into assembly increases portability and reduces dependencies
on additional files
-
Add .resources or .resx files to Project by selecting Project\Add Existing Item
-
Can create assemblies only containing resources – useful where likely to have
to update resource data but not rest of application
-
Add resource files to Empty Project (from New Project menu)
Satellite Assemblies
-
Permit different sets of resources to be loaded at runtime based on
CurrentUICulture setting
-
To create, incorporate alternative sets of appropriately named resources into
app
-
To be incorporated into satellite the resource file must be specially named
-
Invariant culture resource file may be called MyResource.resx
-
Alternative natural German would be called MyResource.de.resx
-
Luxembourg specific would be called MyResource.de-LU.resx
-
Visual Studio .NET compiles resources into separate satellite assemblies within
an appropriate directory structure
Retrieving Resources
-
Use ResourceManager class to retrieve embedded resources
-
Create ResourceManager specifying base name of embedded resource file and
containing assembly – resulting instance dedicated to embedded resource file
-
Base name = namespace containing file and filebame without extensions, e.g.
myResources.de-DE.resx in Namespace1 has base name of Namespace1.myResources
// Obtain resources from same
assembly
ResourceManager myManager = new
ResourceManager(“myNamesapce.myResources”,
this.GetType().Assembly);
// Obtain resources from another
assembly
System.Reflection.Assembly
myResources;
myResources =
System.Reflection.Assembly.Load(“ResAssembly”);
ResourceManager myManager = new
ResourceManager(“myNamesapce.myResources”,
myResources);
·
To retrieve string use ResourceManager.GetString()
·
To retrieve objects and images use ResourceManager.GetObject()
converting returned item to correct type
·
When culture specific satellite assemblies exist the ResourceManager
automatically loads correct resources based on CurrentUICulture setting
Shared Assemblies
-
Private assembly
-
used by one app
-
most common type
-
trouble free to create
-
integral part of app (packaged within it)
-
no versioning or identity issues
-
Note – can create assemblies used in multiple projects (e.g. DLL containing
custom controls), but these are still private as each assembly using this DLL
has its own private copy of the DLL residing in its project folder
-
Normally use private, only use shared assemblies where valid reason to do so
-
Shared assembly – used by multiple apps
-
Only one copy of DLL on machine, stored in GAC (Global Assembly Cache)
-
Why install to GAC
-
Shared location
-
Security – GAC located in C:\WINNT folder so given high level
-
Side-by-side versioning – can install multiple versions of same assembly to GAC
and apps locate and use appropriate version
-
Require strong naming – guarantees unique identity
-
Identity of assembly – name, version and culture
-
Public key or public/private pair
-
To sign assembly with strong name
-
Generate key pair using sn.exe
sn –k myKey.snk
-
Open Assembly Info file for project and verify version number is correct
-
Set AssemblyKeyFileAttribute to file generated by sn.exe
<Assembly:
AssemblyKeyFile(“..\\..\\myKey.snk”);
o
Sign assembly with string Nme
o
Run gacutil.exe with /i to specify assembly to install
gacutil /i
myAssembly.dll
Lesson 2 – Configuration and Optimisation
The Configuration File
-
XML file containing info on app configuration
-
Named <name>.<extension>.config where <name> = app name and
<extension> = app extension (e.g. .exe)
-
Located in same folder as assembly it configures
-
Basic structure:
<?xml version=”1.0” encoding=”utf-8”
?>
<configuration>
<!--
configured elements go here -->
</configuration>
-
No required content for config file – all elements optional
-
High level config file schema elements
-
<startup> - contains <requiredRuntime> that specifies version of
CLR to use
-
<runtime> - assembly binding and garbage collection behaviour
-
<system.runtime.remoting> - configuration of channels and remote objects
-
<system.net> - info for Internet apps
-
<mscorlib> - contains <cryptogtraphySettings> element that controls
how app uses cryptography
-
<configSections> - custom config settings
-
<system.diagnostics> - config Trace and Debug classes
Dynamic Properties
-
Allow configuration of startup values for objects in app
-
Map object properties to entries in config file
-
Retrieve values from file at runtime
-
Useful for properties likely to change during apps lifetime (e.g. DB connection
string)
-
Can only store string types (or values that can be explicitly converted to
string)
Using Properties Window To Configure Properties
-
Use Properties windows to set properties of UI elements to be configurable
-
Add desired properties to controls DynamicProperties node
-
Associate key with desired property. This key corresponds to appropriate value
to return from config file
-
Default format is <control>.<propertyname> e.g.
<add key=”Button1.Text”
value=”Button1”>
appears in config file to configure
Text attribute of Button1 control.
Setting / Retrieving Dynamic Properties Manually
-
Useful for non-UI elements
-
Access using AppSettingsReader class
//Create
AppSettingsReader
System.Configuration.AppSettingsReader
myReader = new
System.Configuration.AppSettingsReader();
// Create a
widget
Widget myWidget = new
Widget();
// Retrieve dynamic
property
myWidget.Text =
myReader.GetValue(“DynamicWidget.Text”,
typeof(System.String).ToString());
-
Attempt to read key not present in config file causes InvalidOperationException
-
Key data pairs held in <add> elements within <appSettings>
<appSettings>
<add
key=”Widget.Visible” value=”True”/>
<add
key=”Widget.Text” value=”Hello, world”/>
</appSettings>
Optimise performance
o
Avoid late binding
-
avoid use of object data types
-
unnecessary conversions resource expensive and slow
-
Avoid global variables
-
Locals allocated in memory region that is easier for code to access
-
Only use globals for truly global needs
-
Constants used fro frequently used values improves efficiency
o
Be wary of loops
-
Most operation-intensive regions of app – merit special attention
-
Design loops so fewest ops required
1.
Measure performance data
2.
Identify bottlenecks
3.
Tune code
4.
Repeat
Measuring performance
-
Use perfmon.exe
-
Use Trace statements
Compiler Optimisations
-
Does not take place of careful coding
-
Optimisations drop down menu in Configuration Properties folder
-
On dialog set Optimize Code to True
-
Can make apps difficult to debug (IL is rearranged)
Lesson 3 – Security
-
Overall system security policy set by administrator
-
what kind of code machine allowed to execute
-
whether particular assembly is trusted, if so what kind of trust
-
Security policy set by administrator cannot be overridden by code
-
Use security to further protect app within bounds set by administrator
-
Role based to authorise users
-
Code access security to protect code from unauthorised users
-
Authorisation either
-
Imperative – permission to execute demanded at runtime
-
Declarative – permissions required by assembly specified in manifest
Permissions
-
Primary security objects
-
Represents
-
User
-
Identity
-
Code resource
-
Implements IPermission interface
-
Copy – Creates and returns identical copy of permission
-
Demand – Walks call stack throwing SecurityException if all callers in call
stack have not been granted the permission
-
Intersect – Creates and returns permission that is intersection of two
permissions
-
IsSubsetOf – Determines if current permission is subset of specified permission
-
Union - Creates and returns permission that is union of two permissions
Role Based Authorisation
-
Grants access to app or resources based on identity and role of user
-
Authenticated users represented by Principal object
-
Contains info on identity and role
-
Validate Principal object against PrincipalPermission object to protect
sensitive parts of app from unauthorised users
-
Can use Windows built-in security to verify identity and role of user by
associating WindowsPrincipal object (the currently logged onuser) with the apps
principal policy
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrinciplal);
-
WindowsPrincipal contains reference to WindowsIdentity object (the current
user)
-
Obtain info on current user via WindowsIdentity
-
WindowsIdentity returned by WindowsPrincipal as IIdentity interface – must
explicitly convert to WindowsIdentity
WindowsPrincipla
myPrincipal;
myPrincipal = (WindowsPrincipal)
System.Threading.Thread.CurrentPrincipal;
WindowsIdentity
myIdentity;
myIdentity = (WindowsIdentity)
myPrincipal.Identity;
MessageBox.Show(myIdentity.Name);
Imperative Security
-
Use PrincipalPermission to perform imperative security checks
-
Specifies and identity and role
-
Demands current user match name and role specified
// Create principal permission for
manager named megan
PrincipalPermission myPermission = new
PrincipalPermission(“Megan”,
“Manager”);
// Ensure current user is manager named
megan
myPermission.Demand();
-
Use Union to combine permissions
// Create principal permission for
manager named megan
PrincipalPermission Permission1 = new
PrincipalPermission(“Megan”,
“Manager”);
// Create principal permission for
group manager named
// ann
PrincipalPermission Permission2 = new
PrincipalPermission(“Ann”, “Group
Manager”);
// Create union
PrincipalPermission Permission3 =
(PrincipalPermission)
Permission2.Union(Permission1);
// Ensure current user is manager named
megan and
// group manager named
ann
Permission3.Demand();
-
Can specify null for name or role – validate only name of role of permission
// Create permission to check user is a
manager
PrincipalPermission myPermission = new
PrinicpalPermission(null,
“Manager”);
-
Can authenticate membership of Windows built-in roles such as Administrators –
precede role with BUILTIN\
-
// Create permission to check user is
an Administrator
PrincipalPermission myPermission = new
PrinicpalPermission(null,
“BUILTIN\\Administrators”);
Declarative Security
-
Every Permission object has corresponding attribute
-
Attach attributes to classes and members to control access
-
Attributes emitted into metadata – enables administrators to decide if assembly
allowed to execute
-
Permission attribute constructor requires SecurityAction – usually a Demand
action
[PrincipalPermission(SecurityAction.Demand,
Name=”Joe”, Role=”Clerk”)]
public void
MyMethod()
{
}
Code Access Security
-
Prevent code being used by unauthorised callers
-
Communicate security requirements to system administrator
-
Based on permissions – represent system resources and their access
-
e.g. app writes to file, ensure unauthorised callers do not have access to that
resource to prevent damage to file system, protect access to file with
FileIOPermission object
-
Some of the available code access permissions
-
DirectoryServicesPermission – access to Active Directory
-
EnvironmentPermission – access to environment variables
-
EventLogPermission – access to event logs
-
FileDialogPermission – access to files and folders through file dialog box
-
FileIOPermission – access to file system
-
OleDbPermission – access to OleDb database
-
PrintingPermission – access to printer
-
ReflectionPermission – access to System.Reflection class
-
RegistryPermission – access to registry
-
SecurityPermission – ability to execute code, manipulate threads and principals
and call unmanaged code
-
SQLClientPermission – access to SQL Server database
-
UIPermission – access to user interface
-
Every code access permission has different set of overloaded constructors to
configure resource it protects
FileIOPermission myPermission = new
FileIOPermission(
FileIOPermissionAccess.Write
,
“C:\\myFile.txt”);
-
Unrestricted access provided by PermissionState.Unrestricted flag
-
Use PermissionState.None to create permission with no access
ReflectionPermission myPermission = new
ReflectionPermission(PermissionState.Unrestricted);
UIPermission anotherPermission = new
UIPermission(PermissionState.None);
-
Can be used either imperatively or declaratively
Imperative Security
-
Primary method to enforce security is Demand()
-
Permission to access resources granted by CLR by checking security policy for
assembly as set by system administrator
-
Demand() walks stack ensuring every caller has been granted permission to
access resource represented by permission object
// Create permission object
representing unrestricted
// access to file
system
FileIOPermission myPermission = new
FileIOPermission(Permissionstate.Unrestricted);
// Verify all callers to code have
unrestricted access
// to file system
myPermission.Demand();
-
Use Deny() to deny callers permission to access protected resources, even if
they granted permission by the CLR
// Create permission object
representing unrestricted
// access to file
system
FileIOPermission myPermission = new
FileIOPermission(Permissionstate.Unrestricted);
// Denies access to the file system
from this method
myPermission.Deny();
-
PermitOnly() restricts access to the specified resource
// Create permission object
representing only write
// access to
c:\myFile.txt
FileIOPermission myPermission = new
FileIOPermission(FileIOPermission.Write
,
“C:\\myFilt.txt”);
// Only allow write access to
c:\myFile.txt, deny all
// else
myPermission.PermitOnly();
-
Use Assert() to declare method has permission to access resource – Demand()
stack traversal will halt with satisfaction when Assert() reached
-
Use Assert() with care – potentially allows untrusted code to access resources
-
Assert() can bypass system security policy – assembly must be given appropriate
permission before issuing Assert()
// Create permission object
representing unrestricted
// access to file
system
FileIOPermission myPermission = new
FileIOPermission(Permissionstate.Unrestricted);
// Assert that this method has
unrestricted access to
// file system
myPermission.Assert();
-
Use static Revert() to remove any previously granted Deny, Assert or PermitOnly
calls
Declarative Security
-
Similar to declarative code access, instead of specifying role you must specify
SecurityAction represented by attribute
// Deny fileIOPermission to
class
[FileIOPermission(SecurityAction.Deny)]
public class
aClass
{
}
-
SecurityAction.Demand, SecurityAction.Deny, SecurityAction.Assert,
SecurityAction.PermitOnly correspond to Demand, Deny, Assert and PermitOnly of
relevant permission
-
SecurityAccess.LinkDemand only requires immediate caller to have been granted
appropriate permission
-
SecurityAccess.InheritanceDemand requires any inherited class or overriding
method must have appropriate permission
-
Can use permission attributes against entire assembly
-
SecurityAction.RequestMinimum – makes request to CLR to be granted requested
permission, if not granted assembly does not run
-
SecurityAction.RequestOptional – makes request to CLR to be granted requested
permission, if not granted assembly still runs
-
SecurityAction.RequestRefuse – requests assembly be denied specified permission
[assembly:
FileIOPermission(SecurityAction.RequestMinimum)]
-
Can set properties for permission attribute
[FileIOPermission(SecurityAction.Assert,
Write=”C:\\myFile.txt”)]
public void
WriteFile()
{
}
Exception Handling and Imperative Security
-
Security failure throws SecurityException
-
Imperative security should be wrapped in exception handling code permitting app
to degrade gracefully
-
Foreseeable exceptions should not go unhandled
|