Strongly Typed Access to Embedded Resources - c#

I'm trying to establish access to an embedded SQL resource file I've created in a Class Library. However, I'm not sure where to go from here.
I've accessed the resource using:
Assembly.GetExcecutingAssembly().GetManifestResourceStream("InsertTest.sql");
My understanding is that there is a way to access them in a strongly typed fashion, but I can't seem to get a handle on the project or the solution to browse through their respective properties or resources programatically.
What am I missing?

Although I did get some great suggestions (see Philip Daniels' answer - good stuff), none of them really addressed my specific concerns. However, I found that the easiest way to accomplish this was to do the following:
Right click your project and select 'Properties'
Select the 'Resources' tab. Create a new resources file if necessary.
In the upper left hand corner there is a drop down that defaults to 'Strings'. Click this box and choose 'Files'.
Drag and drop the resource file you'd like to embed in the project.
You can now access a strongly typed resource using the following syntax:
Project.Properties.Resources.ResourceName;
In my situation, this worked perfectly as I am storing inline SQL in these files and it returns the sql embedded in the file. Keep in mind, however, that by defaults these resources are linked and not embedded, but you can change their property to set them to embedded.
Hope this helps someone!

You're almost there. I have a couple of functions I use for this. You can do somehting very similar for images. I'm not sure it's worth creating properties like you want (you can do that through the Resources tab of the project properties if you insist).
/// <summary>
/// Gets an open stream on the specified embedded resource. It is the
/// caller's responsibility to call Dispose() on the stream.
/// The filename is of the format "folder.folder.filename.ext"
/// and is case sensitive.
/// </summary>
/// <param name="assembly">The assembly from which to retrieve the Stream.</param>
/// <param name="filename">Filename whose contents you want.</param>
/// <returns>Stream object.</returns>
public static Stream GetStream(Assembly assembly, string filename)
{
string name = String.Concat(assembly.GetName().Name, ".", filename);
Stream s = assembly.GetManifestResourceStream(name);
return s;
}
/// <summary>
/// Get the contents of an embedded file as a string.
/// The filename is of the format "folder.folder.filename.ext"
/// and is case sensitive.
/// </summary>
/// <param name="assembly">The assembly from which to retrieve the file.</param>
/// <param name="filename">Filename whose contents you want.</param>
/// <returns>String object.</returns>
public static string GetFileAsString(Assembly assembly, string filename)
{
using (Stream s = GetStream(assembly, filename))
using (StreamReader sr = new StreamReader(s))
{
string fileContents = sr.ReadToEnd();
return fileContents;
}
}

On a resource file you won't be able to have intellisense to build your sql script compare to have them as separate files in your project. You can create a helper class to access them in a strong type fashion:
public class Scripts
{
public static string Sql1
{
get
{
return GetResource("sql1.sql");
}
}
public static string Sql2
{
get
{
return GetResource("sql2.sql");
}
}
private static string GetResource(string name)
{
var assembly = Assembly.GetExecutingAssembly();
using(var stream = new StreamReader(assembly.GetManifestResourceStream("Myproject.Sql." + name)))
{
return stream.ReadToEnd();
}
}
}
For example, in Dapper, you can access your scripts like this:
using(var db = new SqlConnection("yourconnectionstring")){
db.Open();
var results = db.Query(Scripts.Sql1);
}

Related

How use C# in "Script Task" to get files from Input folder in Order by "Date Modified" [duplicate]

i have an folder, in which i receive .csv files for every half hour with time stamps. Now, i need to take the latest file from the available files and import it into sql server.
For Example
in my source folder, i have
test_01112012_120122.csv
test_01112012_123022.csv
test_01112012_123555.csv
now i need to fetch the latest file and import that file into sql server with the help of SSIS.
Thanks
satish
The code from #garry Vass, or one like it, is going to be needed even if you're using SSIS as your import tool.
Within SSIS, you will need to update the connection string to your flat file connection manager to point to the new file. Ergo, you need to determine what is the most recent file.
Finding the most recent file
Whether you do it by file attributes (Garry's code) or slicing and dicing of file names is going to be dependent upon what your business rules are. Is it always the most recently modified file (attribute) or does it need to be based off the file name being interpreted as a sequence. This matters if the test_01112012_120122.csv had a mistake in it and the contents are updated. The modified date will change but the file name will not and those changes wouldn't get ported back into the database.
I would suggest you create 2 variables of type String and scoped to the package named RootFolder and CurrentFile. Optionally, you can create one called FileMask if you are restricting to a particular type like *.csv. RootFolder would be the base folder you expect to find files in C:\ssisdata\MyProject. CurrentFile will be assigned a value from a script of the fully qualified path to the most recently modified file. I find it helpful at this point to assign a design-time value to CurrentFile, usually to the oldest file in the collection.
Drag a Script Task onto the Control Flow and set as your ReadOnlyVariable User::RootFolder (optionally User::FileMask). Your ReadWriteVariable would be User::CurrentFile.
This script would go inside the public partial class ScriptMain: ... braces
/// <summary>
/// This verbose script identifies the most recently modified file of type fileMask
/// living in RootFolder and assigns that to a DTS level variable.
/// </summary>
public void Main()
{
string fileMask = "*.csv";
string mostRecentFile = string.Empty;
string rootFolder = string.Empty;
// Assign values from the DTS variables collection.
// This is case sensitive. User:: is not required
// but you must convert it from the Object type to a strong type
rootFolder = Dts.Variables["User::RootFolder"].Value.ToString();
// Repeat the above pattern to assign a value to fileMask if you wish
// to make it a more flexible approach
// Determine the most recent file, this could be null
System.IO.FileInfo candidate = ScriptMain.GetLatestFile(rootFolder, fileMask);
if (candidate != null)
{
mostRecentFile = candidate.FullName;
}
// Push the results back onto the variable
Dts.Variables["CurrentFile"].Value = mostRecentFile;
Dts.TaskResult = (int)ScriptResults.Success;
}
/// <summary>
/// Find the most recent file matching a pattern
/// </summary>
/// <param name="directoryName">Folder to begin searching in</param>
/// <param name="fileExtension">Extension to search, e.g. *.csv</param>
/// <returns></returns>
private static System.IO.FileInfo GetLatestFile(string directoryName, string fileExtension)
{
System.IO.DirectoryInfo directoryInfo = new System.IO.DirectoryInfo(directoryName);
System.IO.FileInfo mostRecent = null;
// Change the SearchOption to AllDirectories if you need to search subfolders
System.IO.FileInfo[] legacyArray = directoryInfo.GetFiles(fileExtension, System.IO.SearchOption.TopDirectoryOnly);
foreach (System.IO.FileInfo current in legacyArray)
{
if (mostRecent == null)
{
mostRecent = current;
}
if (current.LastWriteTimeUtc >= mostRecent.LastWriteTimeUtc)
{
mostRecent = current;
}
}
return mostRecent;
// To make the below code work, you'd need to edit the properties of the project
// change the TargetFramework to probably 3.5 or 4. Not sure
// Current error is the OrderByDescending doesn't exist for 2.0 framework
//return directoryInfo.GetFiles(fileExtension)
// .OrderByDescending(q => q.LastWriteTimeUtc)
// .FirstOrDefault();
}
#region ScriptResults declaration
/// <summary>
/// This enum provides a convenient shorthand within the scope of this class for setting the
/// result of the script.
///
/// This code was generated automatically.
/// </summary>
enum ScriptResults
{
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success,
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
};
#endregion
}
Updating a Connection Manager
At this point, our script has assigned a value to the CurrentFile variable. The next step is to tell SSIS we need to use that file. In your Connection Manager for your CSV, you will need to set an Expression (F4 or right click and select Properties) for the ConnectionString. The value you want to assign is our CurrentFile variable and the way that's expressed is #[User::CurrentFile]
Finally, these screen shots are based on the upcoming release of SQL Server 2012 so the icons may appear different but the functionality remains the same.
Assuming that you wanted to use C#, to get the newest file in a given directory, you can use a method like this...
private static FileInfo GetLatestFile(string directoryName, string fileExtension)
{
DirectoryInfo directoryInfo = new DirectoryInfo(directoryName);
return directoryInfo.GetFiles(fileExtension)
.OrderByDescending(q => q.LastWriteTimeUtc)
.FirstOrDefault();
}
This method is called like...
FileInfo file = GetLatestFile( "C:\myDirectory", "*.csv");
And it returns a FileInfo instance (or null) of the file with the most recent write time. You can then use the FileInfo instance to get the name of the file and so on for your processing...

How to get a method/property description? [C#] [duplicate]

I'm looking for a way to programmatically get the summary portion of Xml-comments of a method in ASP.net.
I have looked at the previous related posts and they do not supply a way of doing so in a web environment.
I can not use any 3rd party apps and due to a web environment, Visual studio plugin's aren't much use either.
The closest thing I have found to a working solution was the JimBlackler project, but it only works on DLL's.
Naturally, something like 'supply .CS file, get XML documentation' would be optimal.
Current situation
I have a web-service and trying to dynamically generate documentation for it.
Reading the Methods, and properties is easy, but getting the Summary for each method is throwing me off a bit.
/// <summary>
/// This Is what I'm trying to read
/// </summary>
public class SomeClass()
{
/// <summary>
/// This Is what I'm trying to read
/// </summary>
public void SomeMethod()
{
}
}
A Workaround - Using reflection on Program.DLL/EXE together with Program.XML file
If you take a look at the sibling .XML file generated by Visual Studio you will see that there is a fairly flat hierarchy of /members/member.
All you have to do is get hold on each method from your DLL via MethodInfo object. Once you have this object you turn to the XML and use XPATH to get the member containing the XML documentation for this method.
Members are preceded by a letter. XML doc for methods are preceded by "M:" for class by "T:" etc.
Load your sibling XML
string docuPath = dllPath.Substring(0, dllPath.LastIndexOf(".")) + ".XML";
if (File.Exists(docuPath))
{
_docuDoc = new XmlDocument();
_docuDoc.Load(docuPath);
}
Use this xpath to get the member representing the method XML docu
string path = "M:" + mi.DeclaringType.FullName + "." + mi.Name;
XmlNode xmlDocuOfMethod = _docuDoc.SelectSingleNode(
"//member[starts-with(#name, '" + path + "')]");
Now scan childnodes for all the rows of "///"
Sometimes the /// Summary contains extra blanks, if this bothers use this to remove
var cleanStr = Regex.Replace(row.InnerXml, #"\s+", " ");
The XML summary isn't stored in the .NET assembly - it's optionally written out to an XML file as part of your build (assuming you're using Visual Studio).
Consequently there is no way to "pull out" the XML summaries of each method via reflection on a compiled .NET assembly (either .EXE or .DLL) - because the data simply isn't there for you to pull out. If you want the data, you'll have to instruct your build environment to output the XML files as part of your build process and parse those XML files at runtime to get at the summary information.
You could 'document' your method using the System.ComponentModel.DataAnnotations.DisplayAttribute attribute, e.g.
[Display(Name = "Foo", Description = "Blah")]
void Foo()
{
}
then use reflection to pull the description at runtime.
A deleted post, made by #OleksandrIeremenko, on this thread links to this article https://jimblackler.net/blog/?p=49 which was the basis for my solution.
Below is a modification of Jim Blackler's code making extension methods off the MemberInfo and Type objects and adding code that returns the summary text or an empty string if not available.
Usage
var typeSummary = typeof([Type Name]).GetSummary();
var methodSummary = typeof([Type Name]).GetMethod("[Method Name]").GetSummary();
Extension Class
/// <summary>
/// Utility class to provide documentation for various types where available with the assembly
/// </summary>
public static class DocumentationExtensions
{
/// <summary>
/// Provides the documentation comments for a specific method
/// </summary>
/// <param name="methodInfo">The MethodInfo (reflection data ) of the member to find documentation for</param>
/// <returns>The XML fragment describing the method</returns>
public static XmlElement GetDocumentation(this MethodInfo methodInfo)
{
// Calculate the parameter string as this is in the member name in the XML
var parametersString = "";
foreach (var parameterInfo in methodInfo.GetParameters())
{
if (parametersString.Length > 0)
{
parametersString += ",";
}
parametersString += parameterInfo.ParameterType.FullName;
}
//AL: 15.04.2008 ==> BUG-FIX remove “()” if parametersString is empty
if (parametersString.Length > 0)
return XmlFromName(methodInfo.DeclaringType, 'M', methodInfo.Name + "(" + parametersString + ")");
else
return XmlFromName(methodInfo.DeclaringType, 'M', methodInfo.Name);
}
/// <summary>
/// Provides the documentation comments for a specific member
/// </summary>
/// <param name="memberInfo">The MemberInfo (reflection data) or the member to find documentation for</param>
/// <returns>The XML fragment describing the member</returns>
public static XmlElement GetDocumentation(this MemberInfo memberInfo)
{
// First character [0] of member type is prefix character in the name in the XML
return XmlFromName(memberInfo.DeclaringType, memberInfo.MemberType.ToString()[0], memberInfo.Name);
}
/// <summary>
/// Returns the Xml documenation summary comment for this member
/// </summary>
/// <param name="memberInfo"></param>
/// <returns></returns>
public static string GetSummary(this MemberInfo memberInfo)
{
var element = memberInfo.GetDocumentation();
var summaryElm = element?.SelectSingleNode("summary");
if (summaryElm == null) return "";
return summaryElm.InnerText.Trim();
}
/// <summary>
/// Provides the documentation comments for a specific type
/// </summary>
/// <param name="type">Type to find the documentation for</param>
/// <returns>The XML fragment that describes the type</returns>
public static XmlElement GetDocumentation(this Type type)
{
// Prefix in type names is T
return XmlFromName(type, 'T', "");
}
/// <summary>
/// Gets the summary portion of a type's documenation or returns an empty string if not available
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static string GetSummary(this Type type)
{
var element = type.GetDocumentation();
var summaryElm = element?.SelectSingleNode("summary");
if (summaryElm == null) return "";
return summaryElm.InnerText.Trim();
}
/// <summary>
/// Obtains the XML Element that describes a reflection element by searching the
/// members for a member that has a name that describes the element.
/// </summary>
/// <param name="type">The type or parent type, used to fetch the assembly</param>
/// <param name="prefix">The prefix as seen in the name attribute in the documentation XML</param>
/// <param name="name">Where relevant, the full name qualifier for the element</param>
/// <returns>The member that has a name that describes the specified reflection element</returns>
private static XmlElement XmlFromName(this Type type, char prefix, string name)
{
string fullName;
if (string.IsNullOrEmpty(name))
fullName = prefix + ":" + type.FullName;
else
fullName = prefix + ":" + type.FullName + "." + name;
var xmlDocument = XmlFromAssembly(type.Assembly);
var matchedElement = xmlDocument["doc"]["members"].SelectSingleNode("member[#name='" + fullName + "']") as XmlElement;
return matchedElement;
}
/// <summary>
/// A cache used to remember Xml documentation for assemblies
/// </summary>
private static readonly Dictionary<Assembly, XmlDocument> Cache = new Dictionary<Assembly, XmlDocument>();
/// <summary>
/// A cache used to store failure exceptions for assembly lookups
/// </summary>
private static readonly Dictionary<Assembly, Exception> FailCache = new Dictionary<Assembly, Exception>();
/// <summary>
/// Obtains the documentation file for the specified assembly
/// </summary>
/// <param name="assembly">The assembly to find the XML document for</param>
/// <returns>The XML document</returns>
/// <remarks>This version uses a cache to preserve the assemblies, so that
/// the XML file is not loaded and parsed on every single lookup</remarks>
public static XmlDocument XmlFromAssembly(this Assembly assembly)
{
if (FailCache.ContainsKey(assembly))
{
throw FailCache[assembly];
}
try
{
if (!Cache.ContainsKey(assembly))
{
// load the docuemnt into the cache
Cache[assembly] = XmlFromAssemblyNonCached(assembly);
}
return Cache[assembly];
}
catch (Exception exception)
{
FailCache[assembly] = exception;
throw;
}
}
/// <summary>
/// Loads and parses the documentation file for the specified assembly
/// </summary>
/// <param name="assembly">The assembly to find the XML document for</param>
/// <returns>The XML document</returns>
private static XmlDocument XmlFromAssemblyNonCached(Assembly assembly)
{
var assemblyFilename = assembly.Location;
if (!string.IsNullOrEmpty(assemblyFilename))
{
StreamReader streamReader;
try
{
streamReader = new StreamReader(Path.ChangeExtension(assemblyFilename, ".xml"));
}
catch (FileNotFoundException exception)
{
throw new Exception("XML documentation not present (make sure it is turned on in project properties when building)", exception);
}
var xmlDocument = new XmlDocument();
xmlDocument.Load(streamReader);
return xmlDocument;
}
else
{
throw new Exception("Could not ascertain assembly filename", null);
}
}
}
You can use Namotion.Reflection NuGet package to get these information:
string summary = typeof(Foo).GetXmlDocsSummary();
You can look at https://github.com/NSwag/NSwag - source for nuget NSwag.CodeGeneration - it gets summary as well, usage
var generator = new WebApiAssemblyToSwaggerGenerator(settings);<br/>
var swaggerService = generator.GenerateForController("namespace.someController");<br/>
// string with comments <br/>
var swaggerJson = swaggerService.ToJson();
(try ILSPY decompiler against your dll, you check code and comments)
If you have access to the source code you're trying to get comments for, then you can use Roslyn compiler platform to do that. It basically gives you access to all the intermediary compiler metadata and you can do anything you want with it.
It's a bit more complicated than what other people are suggesting, but depending on what your needs are, might be an option.
It looks like this post has a code sample for something similar.

Load multiple resource files into one resource manager

I'm searching for a way to make one resource manager that holds all the data form multiple resource files. Is this even possible? It would be useful for me if yes because I've got like 10+ resources files with translations. I want to make one wrapper class for this and make one resource manager so if I e.g. use rm.GetString("string"); I get this value from one of resource files. I probably think that this is not the best idea but... if you have any good ideas please share here!
I'm trying the following code:
var rm = new ResourceManager("ProjectNameSpace.ResourceName",
Assembly.GetExecutingAssembly());
By doing this I only load resources from file that I specified by: ProjectNameSpace.ResourceName, am I right?
Is there any nice workaround for this or different approach?
This is not exactly what you are asking about, but maybe it will help. This is some cut-down copy-and-paste code from a program I use that reads multiple resource files and creates a combined Dictionary of all of the icons in the resource files.
class Program
{
static void Main(string[] args)
{
IconManager.FindIconsInResources(Resources1.ResourceManager);
//IconManager.FindIconsInResources(Resources2.ResourceManager);
//IconManager.FindIconsInResources(Resources3.ResourceManager);
Image iconImage = IconManager.GetIcon("Incors_office_building_16x16");
}
}
public static class IconManager
{
private static readonly Dictionary<string, ResourceSet> _iconDictionary =
new Dictionary<string, ResourceSet>();
/// <summary>
/// Method to read the resources info for an assembly and find all of the icons and add them
/// to the icon collection.
/// </summary>
public static void FindIconsInResources(ResourceManager resourceManager)
{
// Get access to the resources (culture shouldn't matter, but has to be specified)
ResourceSet resourceSet =
resourceManager.GetResourceSet(CultureInfo.GetCultureInfo("en-us"), true, true);
if (resourceSet == null)
throw new Exception("Unable to create ResourceSet.");
// Top of loop to examine each resource object
foreach (DictionaryEntry dictionaryEntry in resourceSet)
{
// Check it's an icon (or some kind of graphic)
if (!(dictionaryEntry.Value is Bitmap))
continue;
// Get the resource name, which is basically the filename without ".png" and with '-'
// and blanks converted to '_'. Ignore .ico files.
string resourceKey = (string)dictionaryEntry.Key;
if (resourceKey.EndsWith("_ico", StringComparison.Ordinal))
continue;
// Add (or replace) the icon in the icon dictionary
_iconDictionary[resourceKey] = resourceSet;
}
}
/// <summary>
/// Method to get an icon image from one of several resource files.
/// </summary>
public static Image GetIcon(string iconName)
{
ResourceSet resourceSet;
_iconDictionary.TryGetValue(iconName, out resourceSet);
if (resourceSet == null)
return null;
return (Image)resourceSet.GetObject(iconName);
}
}

How to detect pending changes in libgit2sharp?

In libgit2sharp https://github.com/libgit2/libgit2sharp/ how do you check for pending/uncommitted changes?
The following works for me:
///DEPRECATED - see comment from #derptastic
public bool HasUncommittedChanges
{
get
{
using (var repo = new Repository(repositoryRoot))
{
RepositoryStatus status = repo.RetrieveStatus();
return status.IsDirty;
}
}
}
Thanks to #Derptastic for the link to LibGit2Sharp Wiki
The following lines of code will provide the filename and the state of that file.
foreach (var item in repo1.RetrieveStatus())
{
Console.WriteLine(item.FilePath);
Console.WriteLine(item.State);
}
You can use repository.Diff.Compare().
/// <summary>
/// Show changes between the working directory and the index.
/// </summary>
/// <param name = "paths">The list of paths (either files or directories) that should be compared.</param>
/// <returns>A <see cref = "TreeChanges"/> containing the changes between the working directory and the index.</returns>
public virtual TreeChanges Compare(IEnumerable<string> paths = null)
Passing no paths at all should give all changes.

Moving a document library item from one folder to another including version history using c#

Using Sharepoint 2007 object model, I have been looking for an example in C# to move an item from one document library to another on the same server and saving the version history (i.e. SPListItemVersion objects) and metadata (the folders have the same content types, etc).
I was able to accomplish what I wanted to do with the following code:
/// <summary>
/// Adds item to archive
/// </summary>
/// <param name="item">Item to add</param>
/// <param name="destination">Archive path</param>
/// <param name="destination">web site of archive</param>
/// <returns>Result of arhivation process</returns>
public static string ArchiveItem(SPListItem item, string destination, SPWeb web)
{
// Save main meta information for later use:
var author = item.File.Author;
var modifiedBy = item.File.ModifiedBy;
var modified = item.File.TimeLastModified;
var created = item.File.TimeCreated;
// Get destination filename:
var destinationFile = destination + "/" + item.File.Name;
// Copy the item and set properties:
var coppiedFile = web.GetFolder(destination).Files.Add(
destinationFile,
item.File.OpenBinary(),
author,
modifiedBy,
created,
modified
);
coppiedFile.Item["Created"] = created;
coppiedFile.Item["Modified"] = modified;
// Save changes, UpdateOverwriteVersion causes object to save without saving a new version.
coppiedFile.Item.UpdateOverwriteVersion();
// If moving is enabled, delete original item:
item.Delete();
return coppiedFile.ServerRelativeUrl;
}

Categories

Resources