I've got a nice DAL generated using Subsonic. Is there a way I can generate a skeleton for the BLL? I don't want to plug the SS layer directly into my GUI.
I've trudged through both SS forums and it seems that everyone calls the SSS-generated layer a DAL, but they use it as a BLL.
Have you used SS and seperated the DAL and BLL tiers without manually coding the BLL from scratch?
No, but there are some options. You can extend the generated table classes with partial class files to add more logic, and this might be good enough for many smaller applications. You also may need DTO classes as well, and subsonic 3's table classes usually seem to work as DTO objects. You can write additional t4 template files in subsonic 3 to create business classes, one class per table. The code will be a lot like the existing template code so should be pretty easy. You could even take the template code for the table classes in ss3 and use them in ss2 to generate files. It depends on how badly you want to generate a simple set of BLL classes.
Yes I use seperate DAL and BLL except when the project is really small and there is not much of the business logic.
You are right doing all the implementation in BAL for the DAL properties is really tiresome and defeats the code generation goodness of SS. I've created a little console app that goes through DAL and churn out skeleton BLL's:
Here is the code of it. Please remember it is very crude one (I'm pasting it here in hope of getting it scrutinized by SO fellows and improve on it):
class Program
{
static void Main(string[] args)
{
InitTypesDictionary();
ProcessFile("c:\\temp\\myBll", "YOUR_BLL_NAMESPACE");//args[0], args[1]);
Console.ReadLine();
}
private static void InitTypesDictionary()
{
typesMap = new Dictionary<string, string>();
typesMap.Add("System.String", "string");
typesMap.Add("System.Int32", "int");
typesMap.Add("System.Decimal", "decimal");
typesMap.Add("System.Double", "double");
typesMap.Add("System.Guid", "Guid");
typesMap.Add("System.DateTime", "DateTime");
typesMap.Add("System.Boolean", "bool");
typesMap.Add("System.Byte", "byte");
typesMap.Add("System.Short", "short");
typesMap.Add("System.Nullable`1[System.Int32]", "int?");
typesMap.Add("System.Nullable`1[System.DateTime]", "DateTime?");
typesMap.Add("System.Nullable`1[System.Decimal]", "decimal?");
typesMap.Add("System.Nullable`1[System.Double]", "double?");
typesMap.Add("System.Nullable`1[System.Boolean]", "bool?");
}
private static void WriteError(string msg)
{
WriteInfo(msg, ConsoleColor.Red);
}
private static void WriteTypeName(string name)
{
WriteInfo(name, ConsoleColor.Blue);
}
private static void WriteInfo(string info, ConsoleColor cc)
{
ConsoleColor clr = Console.ForegroundColor;
Console.ForegroundColor = cc;
Console.WriteLine(info);
Console.ForegroundColor = clr;
}
private static void ProcessFile(string savePath, string _namespace)
{
Assembly asm = Assembly.GetAssembly(typeof(ROMS.DAL.RomsAdBusiness));
//Assembly asm = Assembly.ReflectionOnlyLoad("ROMS.DAL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
Type[] types = asm.GetTypes();
foreach (Type t in types)
{
if (t.BaseType.Name.Contains("ActiveRecord"))
{
WriteTypeName("Processing " + t.Name);
ProcessType(t, savePath, _namespace);
}
}
}
private static void ProcessType(Type t, string path, string nsp)
{
string className = t.Name.Substring(4);
StringBuilder sbCode = new StringBuilder();
sbCode.Append(imports);
//sbCode.Append(Environment.NewLine);
sbCode.AppendFormat(comments, t.Name, DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss"));
sbCode.AppendFormat(namespaceStart, nsp);
//sbCode.Append(Environment.NewLine);
sbCode.AppendFormat(_class, className);
//sbCode.Append(Environment.NewLine);
sbCode.AppendFormat(dalObject, t.Name);
sbCode.AppendFormat(regionStart, "ctor");
//sbCode.Append(Environment.NewLine);
sbCode.AppendFormat(ctorString, className, t.Name);
sbCode.AppendFormat(ctorStringPK, className, t.Name);
sbCode.AppendFormat(ctorStringObject, className, t.Name);
sbCode.AppendFormat(regionEnd, "");
//sbCode.Append(Environment.NewLine);
PropertyInfo[] properties = t.GetProperties();
//if (properties.Count() > 0)
//{
sbCode.AppendFormat(regionStart, "Properties");
//sbCode.Append(Environment.NewLine);
//}
foreach (PropertyInfo p in properties)
{
if (SkipProperties.Contains(p.Name)) continue;
if (p.Name == className)
sbCode.AppendFormat(propertyValue, GetPropertyTypeName(p.PropertyType.ToString()), p.Name + "Value", p.Name);
else if (p.Name.ToLower().Contains("roms"))
sbCode.AppendFormat(propertyInternal, GetPropertyTypeName(p.PropertyType.ToString()), p.Name);
else
sbCode.AppendFormat(property, GetPropertyTypeName(p.PropertyType.ToString()), p.Name);
//sbCode.Append(Environment.NewLine);
}
sbCode.Append(isNew_Validate_Properties);
//if (properties.Count() > 0)
//{
sbCode.AppendFormat(regionEnd, "");
//sbCode.Append(Environment.NewLine);
//}
sbCode.AppendFormat(regionStart, "methods");
sbCode.Append(saveMethod);
sbCode.Append(deleteMethod.Replace("_CLASSNAME_", className));
sbCode.AppendFormat(regionEnd, "");
//Add Fetch as Collection Methods
sbCode.Append(getCollectionsMethods.Replace("_CLASSNAME_", className).Replace("_DOUBLEQUOTE_", "\""));
//Define Columns Structure
Type cols = t.GetNestedType("Columns");
if (cols != null)
{
StringBuilder sbCols = new StringBuilder(columnsStructStart);
MemberInfo[] fields = cols.GetMembers();
foreach (MemberInfo mi in fields)
{
if (mi.MemberType == MemberTypes.Field)
sbCols.AppendFormat(columnDeclaration, mi.Name);
}
sbCols.Append(columnsStructEnd);
sbCode.Append(sbCols.ToString());
}
sbCode.Append("}_NL_}_NL_");
var fileName = WriteFile(path, nsp, className, sbCode);
WriteInfo("Written file: " + fileName, ConsoleColor.Yellow);
}
private static string GetPropertyTypeName(string s)
{
if (typesMap.ContainsKey(s)) return typesMap[s];
if (s.Contains("Nullable`"))
{
s = s.Substring(s.IndexOf("[") + 1);
s = s.Substring(0, s.IndexOf("]"));
if (typesMap.ContainsKey(s))
return typesMap[s] + "?";
else
return "Nullable<" + s + ">";
}
if (s.StartsWith("System."))
return s.Substring(7);
if (s.LastIndexOf(".") > 0)
return s.Substring(s.LastIndexOf(".") + 1);
return s;
}
private static string WriteFile(string path, string nsp, string typeName, StringBuilder sbCode)
{
string filename = GetFilePath(path, nsp, typeName);
TextWriter tw = new StreamWriter(filename);
StringBuilder sb = sbCode.Replace("_BS_", "{")
.Replace("_BE_", "}")
.Replace("_NL_", Environment.NewLine)
.Replace("_DOUBLEQUOTE_", "\"");
tw.Write(sb.ToString());
tw.Flush();
tw.Close();
return filename;
}
private static string GetFilePath(string path, string nsp, string typeName)
{
path = path.EndsWith("\\") ? path : path + "\\";
path += typeName + ".cs";
return path;
}
static bool IsNullableType(Type theType)
{
return (theType.IsGenericType && theType.
GetGenericTypeDefinition().Equals
(typeof(Nullable<>)));
}
private static string[] SkipProperties = new[]{"IsLoaded", "IsNew", "IsDirty",
"TableName", "ProviderName",
"NullExceptionMessage","InvalidTypeExceptionMessage",
"LengthExceptionMessage",
"AuditId","Schema","ValidateWhenSaving","DirtyColumns","Errors"};
static IDictionary<string, string> typesMap;
static string comments = #"_NL_///<sumary>
///This class uses {0} from YOUR_DAL_NAMESPACE
///Created by MyCodeGen (YOUR_NAME) on {1}
///</sumary>_NL_";
static string dalObject = "_NL_private YOUR_DAL_NAMESPACE.{0} _dalObject;_NL_";
static string namespaceStart = "namespace {0} _NL_ _BS_ _NL_";
static string property = "public {0} {1} _NL_ _BS_ _NL_ get _BS_ return
_dalObject.{1}; _BE_ _NL_ " +
"set _BS_ _dalObject.{1} = value; _BE_ _NL_ _BE_ _NL_";
static string propertyInternal = "internal {0} {1} _NL_ _BS_ _NL_ get _BS_ return
_dalObject.{1}; _BE_ _NL_ " +
"set _BS_ _dalObject.{1} = value; _BE_ _NL_ _BE_ _NL_";
static string propertyValue = "public {0} {1} _NL_ _BS_ _NL_ get _BS_ return
_dalObject.{2}; _BE_ _NL_ " +
"set _BS_ _dalObject.{2} = value; _BE_ _NL_ _BE_ _NL_";
static string _class = "public partial class {0} _NL_ _BS_ ";
static string regionStart = "#region {0} _NL_";
static string regionEnd = "#endregion{0}_NL__NL_";
static string ctorString = "[DebuggerStepThrough]_NL_public {0}() _NL_
_BS__NL__dalObject = new YOUR_DAL_NAMESPACE.{1}(); _NL_ _BE_ _NL_";
static string ctorStringPK = "[DebuggerStepThrough]_NL_public {0}(int pk) _NL_
_BS__NL__dalObject = new YOUR_DAL_NAMESPACE.{1}(pk);_NL__BE__NL_";
static string ctorStringObject = "[DebuggerStepThrough]_NL_public
{0}(YOUR_DAL_NAMESPACE.{1} dalObject) _NL_ _BS__NL__dalObject = dalObject; _NL_
if(_dalObject==null) _NL__dalObject = new YOUR_DAL_NAMESPACE.{1}();_BE_ _NL_";
static string columnsStructStart = #"_NL_#region Columns Struct
public struct Columns
{
";
static string columnsStructEnd=#"
}
#endregion_NL_";
static string columnDeclaration = "public static string
{0}=_DOUBLEQUOTE_{0}_DOUBLEQUOTE_;_NL_";
static string saveMethod = "_NL_public bool Save() _NL__BS__NL_bool ret=IsValid;
_NL_ if(ret)_NL__dalObject.Save(); _NL_ return ret;_NL__BE__NL_";
static string deleteMethod = #"public int Delete()
{
string pkColumn=_dalObject.GetSchema().PrimaryKey.ColumnName;
object pkValue = _dalObject.GetColumnValue(pkColumn);
return ActiveRecord<Roms_CLASSNAME_>.Delete(pkValue);
}
";
static string isNew_Validate_Properties = #"/// <summary>
/// Enquiries underlying database object to know if it is persisted in
///database or not.
/// True if object has never been saved to database, false otherwise
/// </summary>
public bool IsNew
_BS_
get _BS_ return _dalObject.IsNew; _BE_
_BE_
/// <summary>
/// Validates the underlying dataobject for the lengeth, range of the
///columns defined
/// in database. Should be called before pushing object to database
///(before saving or updating).
/// </summary>
public bool IsValid
_BS_
get _BS_ return _dalObject.Validate(); _BE_
_BE_
/// <summary>
/// This string of validation error messages (<br/> seperated)
/// if the object is not valid.
/// </summary>
/// <returns>string</returns>
public string GetErrors
_BS_
get
_BS_
StringBuilder sb=new StringBuilder();
foreach (var v in _dalObject.GetErrors())
sb.AppendFormat(_DOUBLEQUOTE__BS_0_BE_<br/>_DOUBLEQUOTE_, v);
return sb.ToString();
_BE_
_BE__NL_";
static string imports =
#"using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Diagnostics;
using System.Reflection;
using SubSonic;
using YOUR_DAL_NAMESPACE;
";
static string getCollectionsMethods = #"#region Fetch as Collection Methods
///<sumary>
///Returns the collection containing objects of type _CLASSNAME_ corresponding to
_CLASSNAME_Collection
///objects passed
///</sumary>
[DebuggerStepThrough]
public static IList<_CLASSNAME_> _CLASSNAME_s(Roms_CLASSNAME_Collection coll)
{
IList<_CLASSNAME_> list=new List<_CLASSNAME_>();
foreach(var roprof in coll)
list.Add(new _CLASSNAME_(roprof));
return list;
}
/// <summary>
/// Returns the IList<_CLASSNAME_> of _CLASSNAME_ objects
/// </summary>
/// <returns>IList<_CLASSNAME_></returns>
[DebuggerStepThrough]
public static IList<_CLASSNAME_> _CLASSNAME_s()
{
return _CLASSNAME_s(_DOUBLEQUOTE__DOUBLEQUOTE_,null);
}
/// <summary>
/// Returns the IList<_CLASSNAME_> of _CLASSNAME_ objects having
/// value of <see cref=_DOUBLEQUOTE_columnName_DOUBLEQUOTE_/> =
///<see cref=_DOUBLEQUOTE_value_DOUBLEQUOTE_/>
/// </summary>
/// <param name=_DOUBLEQUOTE_columnName_DOUBLEQUOTE_>Name of the column</param>
/// <param name=_DOUBLEQUOTE_value_DOUBLEQUOTE_>Value of the column</param>
/// <returns>IList<_CLASSNAME_></returns>
[DebuggerStepThrough]
public static IList<_CLASSNAME_> _CLASSNAME_s(string columnName, object value)
{
IList<_CLASSNAME_> collection = new List<_CLASSNAME_>();
Roms_CLASSNAME_Collection coll = null;
if (!string.IsNullOrEmpty(columnName))
{
Roms_CLASSNAME_ obj = new Roms_CLASSNAME_();
columnName = obj.GetType().GetNestedType(
_DOUBLEQUOTE_Columns_DOUBLEQUOTE_).
GetField(columnName).GetValue(obj).ToString();
}
if (!string.IsNullOrEmpty(columnName) && value != null)
{
coll = (new Roms_CLASSNAME_Collection()).Where(columnName,
value).Load();
}
else
{
coll = (new Roms_CLASSNAME_Collection()).Load();
}
if (coll != null)
foreach (var v in coll)
collection.Add(new _CLASSNAME_(v));
return collection;
}
#endregion
";
PS:- Please take care of YOUR_DAL_NAMESPACE, YOUR_BLL_NAMESPACE and YOUR_NAME placeholders if ever you try it.
Related
Are there any chances to have the MultiRecordEngine set the line number for each record?
I read the documentation and found that the Engine has a LineNumber property, but I couldn't find a way to use it.
What I would like to have:
i.e.:
[FixedLengthRecord]
public class Employee
{
public int LineNumber; // <-- setup by the engine while reading the file
[FieldFixedLength(1)]
public string Type = "2";
[FieldFixedLength(6)]
[FieldTrim(TrimMode.Left, "0")]
public int ID;
}
Or... can I rely on the index of the record in the collection created by the Engine.ReadFile?
i.e.:
static void Main(string[] args)
{
var engine = new MultiRecordEngine(CustomSelector, _types);
var obj = engine.ReadFile("order.txt");
// obj.GetValue(100) returns same record found on the 101th line in the file?
}
You can use the AfterReadRecord event to set the LineNumber property.
Here is a working example
public class Employee
{
[FieldIgnored]
public int LineNumber; // <-- setup by the engine while reading the file
[FieldFixedLength(1)]
public string Type = "2";
[FieldFixedLength(6)]
[FieldTrim(TrimMode.Left, "0")]
public int ID;
}
class Program
{
static void Main(string[] args)
{
var engine = new FileHelperEngine<Employee>();
engine.AfterReadRecord += engine_AfterReadRecord;
Employee[] records = engine.ReadString("2000003" + Environment.NewLine
+ "5000006");
Employee firstRecord = records[0];
Assert.AreEqual(1, firstRecord.LineNumber);
Assert.AreEqual("2", records[0].Type);
Assert.AreEqual(3, records[0].ID);
Employee secondRecord = records[1];
Assert.AreEqual(2, secondRecord.LineNumber);
Assert.AreEqual("5", records[1].Type);
Assert.AreEqual(6, records[1].ID);
Console.Read();
}
static void engine_AfterReadRecord(EngineBase engine, AfterReadEventArgs<Employee> e)
{
e.Record.LineNumber = engine.LineNumber;
}
}
I have a scenario in which I'm creating a mapping utility through which we can map DataReader to entities.
Mapper.CreateMap<IDataReader, T>();
List<T> tList = Mapper.Map<List<T>>(reader);
return tList;
This is working fine if the entity has same columns as in the stored procedure's output. However, I'm working on an some old code where column names are not matching. So I created an attribute through which I could specify corresponding column from sprocs. I specify them using code like this
[DBColumn('EmployeeName')]
public string EmpName { get; set; }
Is there any way I can achieve this using generics/reflection? Note that I have multiple such instances and I'm building an utility. So I can not use ForMember method to achieve that.
UPDATE: I tried creating a custom converter like this. However, my convert function is not getting called at all.
Custom converter
public class CustomConverter<T> : ITypeConverter<System.Data.IDataReader, T>
{
private ResolutionContext _Context = null;
private Dictionary<string, string> _CustomProps { get; set; }
public T Convert(ResolutionContext context)
{
_Context = context;
if (_Context.SourceValue != null &&
!(_Context.SourceValue is System.Data.IDataReader))
{
string message = "Value supplied is of type {0} but expected {1}.\n" +
"Change the type converter source type, or redirect " +
"the source value supplied to the value resolver using FromMember.";
throw new AutoMapperMappingException(_Context, string.Format(
message, typeof(System.Data.IDataReader), _Context.SourceValue.GetType()));
}
_CustomProps = new Dictionary<string, string>();
foreach (PropertyInfo propInfo in context.DestinationType.GetProperties())
{
if (propInfo.CustomAttributes.Any(attr => attr.AttributeType == typeof(DBColumn)))
{
DBColumn propertyValue = (DBColumn)propInfo.GetCustomAttribute(typeof(DBColumn));
_CustomProps.Add(propertyValue.ColumnName, propInfo.Name);
}
}
//return base.Convert(context);
return ConvertCore((System.Data.IDataReader)context.SourceValue);
}
protected T ExistingDestination
{
get
{
if (_Context == null)
{
string message = "ResolutionContext is not yet set. " +
"Only call this property inside the 'ConvertCore' method.";
throw new InvalidOperationException(message);
}
if (_Context.DestinationValue != null &&
!(_Context.DestinationValue is T))
{
string message = "Destination Value is of type {0} but expected {1}.";
throw new AutoMapperMappingException(_Context, string.Format(
message, typeof(T), _Context.DestinationValue.GetType()));
}
return (T)_Context.DestinationValue;
}
}
protected T ConvertCore(System.Data.IDataReader source)
{
T obj = ExistingDestination;
if (obj != null)
{
foreach (KeyValuePair<string, string> keyValuePair in _CustomProps)
{
PropertyInfo prop = obj.GetType().GetProperty(keyValuePair.Key, BindingFlags.Public | BindingFlags.Instance);
if (null != prop && prop.CanWrite)
{
prop.SetValue(obj, System.Convert.ChangeType(source[keyValuePair.Value], prop.PropertyType));
}
}
}
return obj;
}
I'm specifying to use this CustomConverter in below statement.
Mapper.CreateMap<IDataReader, T>().ConvertUsing<CustomConverter<T>>();
List<T> tList = Mapper.Map<List<T>>(reader);
return tList;
Please let me know, where I'm going wrong
I am using FileSystemWatcher to monitor any changes in the app.config file. And also, writing to the config file.
Here is my code :
MyApplication is the main project and DataCache is a clas library referenced in MyApplication.
using System;
using System.Threading;
using System.IO;
namespace MyApplication
{
public class Program
{
public static string rootFolderPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
public static string configFilePath = Path.Combine(rootFolderPath, "MyApplication.exe.config");static void Main(string[] args)
{
//First Time initializing the config file.
ConfigFileMonitor.SetConfigFileAtRuntime(configFilePath);
//Initializing the config file monitor on a separate thread.
Thread monitorThread = new Thread(ConfigFileMonitor.BeginConfigFilesMonitor);
monitorThread.Start();
WriteToConfigFile();
}
static void WriteToConfigFile()
{
Console.WriteLine(String.Format("Hello {0} {1}", DataCache.Section1Data.FirstNameString, DataCache.Section1Data.LastNameString));
string _firstName, _lastName = string.Empty;
do
{
Console.WriteLine("");
Console.Write("First Name : ");
_firstName = Console.ReadLine();
Console.Write("Last Name : ");
_lastName = Console.ReadLine();
if(_firstName.Length>0)
DataCache.Section1Data.FirstNameString = _firstName;
if(_lastName.Length>0)
DataCache.Section1Data.LastNameString = _lastName;
Console.WriteLine(String.Format("Hello {0} {1}", DataCache.Section1Data.FirstNameString, DataCache.Section1Data.LastNameString));
}
while (true);
}
}
}
using System;
using System.IO;
namespace MyApplication
{
/// <summary>
/// Monitors for any change in the app.config file
/// </summary>
public class ConfigFileMonitor
{
private static FileSystemWatcher _watcher;
private static string _configFilePath = String.Empty;
private static string _configFileName = String.Empty;
/// <summary>
/// Texts the files surveillance.
/// </summary>
public static void BeginConfigFilesMonitor()
{
try
{
string fileToMonitor = Program.configFilePath;
if (fileToMonitor.Length == 0)
Console.WriteLine("Incorrect config file specified to watch");
else
{
_configFileName = Path.GetFileName(fileToMonitor);
_configFilePath = fileToMonitor.Substring(0, fileToMonitor.IndexOf(_configFileName));
}
// Use FileWatcher to check and update only modified text files.
WatchConfigFiles(_configFilePath, _configFileName);
}
catch (Exception e1)
{
Console.WriteLine(e1.Message);
}
}
/// <summary>
/// Watches the files.
/// </summary>
/// <param name="targetDir">The target dir.</param>
/// <param name="filteredBy">The filtered by.</param>
static void WatchConfigFiles(string targetDir, string filteredBy)
{
try
{
_watcher = new FileSystemWatcher();
_watcher.Path = targetDir;
_watcher.Filter = filteredBy;
_watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite;
_watcher.EnableRaisingEvents = true;
_watcher.Changed += new FileSystemEventHandler(FileChanged);
_watcher.WaitForChanged(WatcherChangeTypes.Changed);
}
catch (Exception e1)
{
Console.WriteLine(e1.Message);
}
}
/// <summary>
/// Handles the Changed event of the File control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.IO.FileSystemEventArgs"/> instance containing the event data.</param>
protected static void FileChanged(object sender, FileSystemEventArgs e)
{
try
{
_watcher.EnableRaisingEvents = false;
string filechange = e.FullPath;
Console.WriteLine("Configuration File: " + filechange + "changed");
//Since the file is changed - We have reload the configuration settings again.
SetConfigFileAtRuntime(Path.Combine(Program.rootFolderPath, "MyApplication.exe.config"));
Console.WriteLine(String.Format("New Name : {0} {1}", DataCache.Section1Data.FirstNameString, DataCache.Section1Data.LastNameString));
_watcher.EnableRaisingEvents = true;
}
catch (Exception e1)
{
Console.WriteLine(e1.Message);
}
}
/// <summary>
/// Sets the config file at runtime.
/// </summary>
/// <param name="configFilePath"></param>
public static void SetConfigFileAtRuntime(string configFilePath)
{
string runtimeconfigfile;
try
{
if (configFilePath.Length == 0)
Console.WriteLine("Please specify a config file to read from ");
else
{
runtimeconfigfile = configFilePath;
_configFileName = Path.GetFileName(configFilePath);
_configFilePath = configFilePath.Substring(0, configFilePath.IndexOf(_configFileName));
}
// Specify config settings at runtime.
//System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
DataCache.DataConfigSection.config = System.Configuration.ConfigurationManager.OpenExeConfiguration(configFilePath);
//Similarly you can apply for other sections like SMTP/System.Net/System.Web etc..
//But you have to set the File Path for each of these
//config.AppSettings.File = runtimeconfigfile;
//This doesn't actually going to overwrite you Exe App.Config file.
//Just refreshing the content in the memory.
DataCache.DataConfigSection.config.Save(System.Configuration.ConfigurationSaveMode.Modified);
//Refreshing Config Section
//ConfigurationManager.RefreshSection("appSettings");
System.Configuration.ConfigurationManager.RefreshSection("MySectionGroup/Section1");
DataCache.Section1Data.configSection1 = null;
}
catch (Exception e1)
{
Console.WriteLine(e1.Message);
}
}
}
}
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="MySectionGroup">
<section name="Section1" type="DataCache.DataConfigSection, DataCache" allowLocation="false" allowDefinition="Everywhere"/>
<section name="Section2" type="DataCache.DataConfigSection, DataCache" allowLocation="false" allowDefinition="Everywhere"/>
</sectionGroup>
</configSections>
<MySectionGroup>
<Section1>
<name
firstName ="Pierce"
lastName ="Brosnan"
/>
</Section1>
</MySectionGroup>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>
Here are the DataCache classes :
using System;
namespace DataCache
{
public sealed class DataConfigSection : System.Configuration.ConfigurationSection
{
public static System.Configuration.Configuration config = System.Configuration.ConfigurationManager.OpenExeConfiguration(
System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(DataConfigSection)).Location), "MyApplication.exe"));
// Create a "name" element.
[System.Configuration.ConfigurationProperty("name")]
public NameElement Name
{
get
{
return (NameElement)this["name"];
}
set
{
this["name"] = value;
}
}
// Define the "name" element
// with firstName, secondName attributes.
public class NameElement : System.Configuration.ConfigurationElement
{
[System.Configuration.ConfigurationProperty("firstName", DefaultValue = "abcd", IsRequired = true)]
public String FirstName
{
get
{
return (String)this["firstName"];
}
set
{
this["firstName"] = value;
}
}
[System.Configuration.ConfigurationProperty("lastName", DefaultValue = "xyz", IsRequired = true)]
public String LastName
{
get
{
return (String)this["lastName"];
}
set
{
this["lastName"] = value;
}
}
}
}
}
namespace DataCache
{
public class Section1Data
{
public static volatile DataConfigSection configSection1;
private static object syncRoot = new System.Object();
public const string Section1ConfigSectionName = "MySectionGroup/Section1";
private Section1Data() { }
public static DataConfigSection ConfigSection1
{
get
{
lock (syncRoot)
{
if (configSection1 == null)
{
DataConfigSection.config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetAssembly(typeof(DataConfigSection)).Location), "MyApplication.exe"));
configSection1 = (DataConfigSection)DataConfigSection.config.GetSection(Section1ConfigSectionName);
}
}
return configSection1;
}
}
public static string FirstNameString
{
get
{
return ConfigSection1.Name.FirstName.ToString();
}
set
{
ConfigSection1.Name.FirstName = value;
DataConfigSection.config.Save();
}
}
public static string LastNameString
{
get
{
return ConfigSection1.Name.LastName.ToString();
}
set
{
ConfigSection1.Name.LastName = value;
DataConfigSection.config.Save();
}
}
}
}
The issue is if there is any change made to the name from console input, FileChanged gets called once and subsequent changes do not fire it. Moreover, if changes are made manually to the config file, it works fine till and events keep firing till a change is made from console.
I am not sure why is this behaving weird. Can anyone help me here.
Thanks,
Monica
Short version would be:
this.Watcher = new FileSystemWatcher();
this.Watcher.Path = this.Dir;
this.Watcher.Filter = this.File;
this.Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
this.Watcher.EnableRaisingEvents = true;
this.Watcher.Changed += this.OnFileChange;
However, here is a bit more complex (and ugly) sample, taken out from the live source in which some additional processing (besides just reading the file) is required.
public partial class FileModule
{
private ConcurrentDictionary<string, InputFileInfo> inputFileList = new ConcurrentDictionary<string, InputFileInfo>();
public FileModule()
{
this.InitializeInputFileWatchers();
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public void EnableOrDisableRaisingEventsForFileWatchers(bool enable)
{
foreach (var el in this.inputFileList)
{
el.Value.Watcher.EnableRaisingEvents = enable;
}
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private void InitializeInputFileWatchers()
{
for (int i = 0; i < this.InputFiles.Count; i++)
{
if (File.Exists(this.InputFiles[i]))
{
InputFileInfo info = new InputFileInfo();
info.Fullpath = ((FileModuleSettings)this.Settings).InputFiles[i];
info.Watcher.Changed += this.OnFileChange;
this.inputFileList.AddOrUpdate(info.Fullpath, info, (e, v) => { return info; });
}
}
}
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
private void OnFileChange(object source, FileSystemEventArgs e)
{
InputFileInfo info;
if (this.inputFileList.TryGetValue(e.FullPath, out info))
{
DateTime lastWriteTime = System.IO.File.GetLastWriteTime(e.FullPath);
if (info.LastHandledChange != lastWriteTime)
{
TimeSpan span = lastWriteTime.Subtract(info.LastHandledChange);
if (span.Days == 0 && span.Hours == 0 && span.Minutes == 0 && span.Seconds == 0 && span.TotalMilliseconds < this.MinimumFileChangePeriod)
{
// Event ignored due to required minimum file change period;
}
else
{
info.LastHandledChange = lastWriteTime;
this.inputFileList.AddOrUpdate(e.FullPath, info, (a, v) => { return info; });
lock (this.readLockerObject)
{
this.ReadFile(e.FullPath);
}
}
}
}
}
private bool ReadFile(string filepath, int count, bool directReading)
{
StreamReader sr = this.OpenStreamReader(file);
if (sr != null)
{
string line;
string[] split;
int signalId;
double value;
while ((line = sr.ReadLine()) != null)
{
// do sth. with line
}
}
}
}
internal class InputFileInfo : IDisposable
{
public string Dir { get; private set; }
public string File { get; private set; }
public FileSystemWatcher Watcher { get; private set; }
public DateTime LastHandledChange { get; set; }
private string fullpath;
public string Fullpath
{
get
{
return this.fullpath;
}
set
{
this.fullpath = BaseHelper.GetFullFilePath(value);
this.Dir = Directory.GetParent(this.fullpath).ToString();
this.File = this.fullpath.Replace(this.Dir + "\\", string.Empty);
this.Watcher = new FileSystemWatcher();
this.Watcher.Path = this.Dir;
this.Watcher.Filter = this.File;
this.Watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
this.Watcher.EnableRaisingEvents = true;
}
}
public void Dispose()
{
if (this.Watcher != null)
{
this.Watcher.Dispose();
this.Watcher = null;
}
}
}
You have very complex code. My code for watcher is about 10 lines.
There is no need to offload initialization of watcher to another thread. Initialize it on main thread. The watcher watches files in background thread and fires the event when change occurs so there is no need to call WaitForChanged() method.
I've checked my working code and compared it with yours and the only two differences are:
1. My filters are: NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName
2. I don't call WaitForChanged() method
3. I have [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] applied to all methods which interact with watcher.
Furthermore, make sure the file you are monitoring is not in one of the system directories... The watcher does not work well with those files. I banged my head up the wall for half a day long because I was trying to watch file on C:.
this is like an interview question given to me by someone, can you tell me whats wrong with it or if there is a better way of doing this. this will be run in a large enterprise. NOTE : Demo.Tasks.Task is a custom object whose deninition is not shown in this code.
using System;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.WebControls;
using System.Collections;
namespace Demo.WebParts
{
/// <summary>
/// Description for MyTasks.
/// </summary>
[DefaultProperty("Text"),
ToolboxData("<{0}:WebPart1 runat=server></{0}:WebPart1>"),
XmlRoot(Namespace="Demo.Tasks")]
public class MyTasks : Microsoft.SharePoint.WebPartPages.WebPart
{
private const string defaultListName = "";
private string listName = defaultListName;
private ArrayList alTasks;
[Browsable(true),
Category("Miscellaneous"),
DefaultValue(defaultListName),
WebPartStorage(Storage.None),
FriendlyName("List Name Filter"),
Description("The name of sps lists to gather tasks from")]
public string ListName
{
get
{
return listName;
}
set
{
listName = value;
}
}
protected override void CreateChildControls()
{
alTasks = new ArrayList();
try
{
SPWeb myWeb = SPControl.GetContextWeb(this.Context);
foreach(SPList list in myWeb.Lists)
{
if(list.BaseTemplate == SPListTemplateType.Tasks)
{
if(list.Title == listName)
{
getTasksFromList(list);
}
}
}
foreach(SPWeb subWeb in myWeb.Webs)
foreach(SPList list in subWeb.Lists)
if(list.BaseTemplate == SPListTemplateType.Tasks)
getTasksFromList(list);
}
catch
{}
}
private void getTasksFromList(SPList list)
{
for(int i=0;i<list.ItemCount;i++)
{
if(list.Items[i]["AssignedTo"].ToString() == this.Context.User.Identity.Name)
{
Demo.Tasks.Task tsk = Tasks.Task.CreateTask();
tsk.Title = list.Items[i]["Title"].ToString();
tsk.DueDate = (DateTime)list.Items[i]["DueDate"];
tsk.Description = list.Items[i]["Description"].ToString();
tsk.Priority = (int)list.Items[i]["Priority"];
alTasks.Add(tsk);
//now update the item
list.Items[i]["LastViewed"] = DateTime.Now;
}
}
}
/// <summary>
/// Render this Web Part to the output parameter specified.
/// </summary>
/// <param name="output"> The HTML writer to write out to </param>
protected override void RenderWebPart(HtmlTextWriter output)
{
try
{
string strHTML = "";
for(int i=0;i<alTasks.Count;i++)
{
Demo.Tasks.Task tsk = (Demo.Tasks.Task)alTasks[i];
strHTML = strHTML + "The task " + tsk.Title + " is due on " + tsk.DueDate + "<BR>" + tsk.Description + "<BR><BR>";
}
output.Write(strHTML);
}
catch
{}
}
}
}
It would be better if you'll give us more info (what doesn't work, etc.).
But in my opinion you should use 'using' when you're working with SPWeb or SPSite. Not doing this sometimes causes strange errors:
using (SPWeb myWeb = SPControl.GetContextWeb(this.Context))
{
foreach (SPList list in myWeb.Lists)
{
if (list.BaseTemplate == SPListTemplateType.Tasks)
{
if (list.Title == listName)
getTasksFromList(list);
}
}
}
using (SPSite site = new SPSite(SiteUrl))
{
foreach (SPWeb subWeb in site.AllWebs)
{
try //should be 1st statement after foreach
{
foreach (SPList list in subWeb.Lists)
{
if (list.BaseTemplate == SPListTemplateType.Tasks)
getTasksFromList(list);
}
}
finally
{
if (subWeb != null)
subWeb.Dispose();
}
}
}
Here you can read about this:
http://blogs.msdn.com/b/rogerla/archive/2009/01/14/try-finally-using-sharepoint-dispose.aspx
I need to add custom handling to a lists' adding event. However, the event does not appear to be firing. I would like my custom handler defined in EventReceivers to fire anytime a new item of the custom type is added to the list.
I would appreciate any suggestions.
Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
namespace MyTestGroupListFeature
{
class MyTestGroupListFeature : SPFeatureReceiver
{
private const string LISTNAME = "Acquisition Groups";
private const string CONTENTTYPE_LISTNAME = "Contenttype List";
private const string FOO = "FOO";
private const string SITE_TEMPLATE_EXTENSION = ".stp";
public override void FeatureInstalled
(SPFeatureReceiverProperties properties)
{
}
public override void FeatureUninstalling
(SPFeatureReceiverProperties properties)
{
FeatureDeactivating(properties);
}
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
try
{
SPWeb web = properties.Feature.Parent as SPWeb;
SPList list = GetList(web, LISTNAME);
SPSite site = web.Site;
site.AllowUnsafeUpdates = true;
SPContentType newCType = CreateSourceSystemContentType(web);
SPList listct = web.Lists[CONTENTTYPE_LISTNAME];
AddEventReceiverToList(listct);
AddContentTypeToList(web, listct, newCType);
}
catch { }
}
/// <summary>
/// Creates a content type for Source System
/// </summary>
private SPContentType CreateSourceSystemContentType(SPWeb site)
{
//Create site columns
string acronymFieldName = site.Fields.Add("Acronym", SPFieldType.Text, true);
SPFieldText acronymField = (SPFieldText)site.Fields.GetFieldByInternalName(acronymFieldName);
acronymField.Group = "AQSIDM Columns";
acronymField.Update();
string nameFieldName = site.Fields.Add("Name", SPFieldType.Text, true);
SPFieldText nameField = (SPFieldText)site.Fields.GetFieldByInternalName(nameFieldName);
acronymField.Group = "AQSIDM Columns";
acronymField.Update();
string descriptionFieldName = site.Fields.Add("Description", SPFieldType.Text, true);
SPFieldText descriptionField = (SPFieldText)site.Fields.GetFieldByInternalName(descriptionFieldName);
descriptionField.Group = "AQSIDM Columns";
descriptionField.Update();
// Get the parent content type.
SPContentTypeId itemCTID = new SPContentTypeId("0x01");
SPContentType itemCT = site.AvailableContentTypes[itemCTID];
//Create SourceSystem content type:
SPContentType sourceSystemCT = new SPContentType(itemCT, site.ContentTypes, "Source System");
sourceSystemCT.Group = "Source System Content Types";
//Add columns to content type
sourceSystemCT = site.ContentTypes[sourceSystemCT.Id];
SPFieldLink acronymLink = new SPFieldLink(acronymField);
sourceSystemCT.FieldLinks.Add(acronymLink);
//
SPFieldLink nameLink = new SPFieldLink(nameField);
sourceSystemCT.FieldLinks.Add(nameLink);
//
SPFieldLink descriptionLink = new SPFieldLink(descriptionField);
sourceSystemCT.FieldLinks.Add(descriptionLink);
//
//sourceSystemCT.Update();
string assemblyName = System.Reflection.Assembly.GetEntryAssembly().FullName;
string ctReceiverName = "MyTestGroupListFeature.EventReceivers";
sourceSystemCT.EventReceivers.Add(SPEventReceiverType.ItemAdding, assemblyName, ctReceiverName);
sourceSystemCT.Update(true);
site.ContentTypes.Add(sourceSystemCT);
return sourceSystemCT;
}
/// <summary>
/// Adds a custom content type to site's list
/// </summary>
private void AddContentTypeToList(SPWeb web, SPList list, SPContentType ct)
{
list.ContentTypesEnabled = true;
list.ContentTypes.Add(ct);
list.Update();
// Add the item:
SPListItem newItem = list.Items.Add();
newItem["Acronym"] = "Acronym Field Added";
newItem.Update();
}
/// <summary>
/// Programmatically add new event receivers
/// </summary>
private void AddEventReceiverToList(SPList list)
{
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
SPEventReceiverDefinition eventReceiver = list.EventReceivers.Add();
eventReceiver.Name = "On Updating";
eventReceiver.Type = SPEventReceiverType.ItemAdding;
eventReceiver.SequenceNumber = 200;
eventReceiver.Assembly = assembly.FullName;
eventReceiver.Class = "MyTestGroupListFeature.EventReceivers";
eventReceiver.Update();
}
}
class EventReceivers : SPItemEventReceiver
{
/// <summary>
/// Test behavior when adding an item
/// </summary>
public override void ItemAdding(SPItemEventProperties properties)
{
base.ItemAdding(properties);
SourceSystem ss = new SourceSystem();
ss.Name = "sharepointss";
ss.Acronym = "sharepoint acronym";
ss.Description = "desc";
ss.EndPoint = new Uri(#"\testURI");
ss.Update("foo");
ss.Create(String.Format("SourceSystem_Create_SP_{0:o}", DateTime.Now));
}
}
}
After you activated the feature, did you verify whether or not the event receiver was attached to the list? This can be done programatically or using tools such as SharePoint Manager.