Access Embedded Resource In Console App - c#

I am embedding a .docx file into my Console App, and I want to be able to distribute the console.exe and have the users be able to access the .docx file inside it.
I have set the .docx file as a resource (see image) - however, if I try to "access" it by using Resources.Test.docx it seems as it if does not exist, and intellisense is not giving it as an option.
How should I do this in a C# console app?
EDIT
In winforms I would embed as resource like this:
static void Main(string[] args)
{
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
string rn1 = new AssemblyName(args.Name).Name + ".docx";
string rs1 = Array.Find(this.GetType().Assembly.GetManifestResourceNames(), element => element.EndsWith(rn1));
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(rs1))
{
Byte[] assemblydata = new Byte[stream.Length];
stream.Read(assemblydata, 0, assemblydata.Length);
return Assembly.Load(assemblydata);
}
}
}
And access the file like this:
Object oFName;
byte[] resourceFile = Properties.Resources.Report;
string destination = Path.Combine(Path.GetTempPath(), "Test.docx");
System.IO.File.WriteAllBytes(destination, resourceFile);
oFName = destination;
EDIT 2
If I try to use the code I use for winforms the AppDomain.CurrentDomain.AssemblyResolve ->
I receive the below errors
A local or parameter named 'args' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
Keyword 'this' is not valid in a static property, static method, or static field initializer

Your first method, with a little bit of modification, should be able to return a resource stream. Here is basically what you have modified a little bit to just read the stream:
public static byte[] GetResourceData(string resourceName)
{
var embeddedResource = Assembly.GetExecutingAssembly().GetManifestResourceNames().FirstOrDefault(s => string.Compare(s, resourceName, true) == 0);
if (!string.IsNullOrWhiteSpace(embeddedResource))
{
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedResource))
{
var data = new byte[stream.Length];
stream.Read(data, 0, data.Length);
return data;
}
}
return null;
}
This method can be called using the resource name and will return all the bytes that are inside the embedded resource.

Related

Checking if the file is rar through its bytes

I am trying to verify that the file is a .rar file through its bytes for security purposes. Th following code is my code the only problem is that the sub-header is not matching with the one generated from the file. I noticed that is different for different file. Could you please explain to me why?
static bool IsRARFile(string filePath)
{
bool isDocFile = false;
//
// File sigs from: http://www.garykessler.net/library/file_sigs.html
//
string msOfficeHeader = "52-61-72-21-1A-07-00-CF";
string docSubHeader = "64-2E-63-73";
using (Stream stream = File.OpenRead(filePath))
{
//get file header
byte[] headerBuffer = new byte[8];
stream.Read(headerBuffer, 0, headerBuffer.Length);
string headerString = BitConverter.ToString(headerBuffer);
if (headerString.Equals(msOfficeHeader, StringComparison.InvariantCultureIgnoreCase))
{
//get subheader
byte[] subHeaderBuffer = new byte[4];
stream.Seek(512, SeekOrigin.Begin);
stream.Read(subHeaderBuffer, 0, subHeaderBuffer.Length);
string subHeaderString = BitConverter.ToString(subHeaderBuffer);
if (subHeaderString.Equals(docSubHeader, StringComparison.InvariantCultureIgnoreCase))
{
isDocFile = true;
}
}
}
return isDocFile;
}
This is because you have just copied a function from somewhere for a different filetype and not every filetype has any notion of a "subheader". You only need to check the main header in the case of RAR.
I also suggest modifying the naming of the variables, it is quite a mismash if a function says it's checking for RAR type and internally all variables refer to DOCs.

How can a custom formatter be build off of a default formatter in Web API?

I'm working on a project in .NET 4 and Web API 2, adding a file upload field to an already-implemented controller. I've found that Web API doesn't support multipart/form-data POST requests by default, and I need to write my own formatter class to handle them. Fine.
Ideally, what I'd like to do is use the existing formatter to populate the model, then add the file data before returning the object. This file upload field is being attached to six separate models, all of which are very complex (classes containing lists of classes, enums, guids, etc.). I've run into a few snags...
I tried implementing it manually using the source code for FormUrlEncodedMediaTypeFormatter.cs as an example. I found that it constructs a list of KeyValue pairs for each field (which I can easily do), then parses them using FormUrlEncodedJson.Parse(). I can't use FormUrlEncodedJson, because it's (for some reason?) marked Internal.
I started implementing my own parser, but when I hit about line 50, I thought to myself: I must be doing something wrong. There must be some way to populate the object with one of the existing Formatters, right? Surely they didn't expect us to write a new formatter for every single model or, even worse, writing our own more-fragile version of FormUrlEncodedJson.Parse()?
What am I missing here? I'm stumped.
// Multipart/form-data formatter adapted from:
// http://stackoverflow.com/questions/17924655/how-create-multipartformformatter-for-asp-net-4-5-web-api
public class MultipartFormFormatter : FormUrlEncodedMediaTypeFormatter
{
private const string StringMultipartMediaType = "multipart/form-data";
//private const string StringApplicationMediaType = "application/octet-stream";
public MultipartFormFormatter()
{
this.SupportedMediaTypes.Add(new MediaTypeHeaderValue(StringMultipartMediaType));
//this.SupportedMediaTypes.Add(new MediaTypeHeaderValue(StringApplicationMediaType));
}
public override bool CanReadType(Type type)
{
return true;
}
public override bool CanWriteType(Type type)
{
return false;
}
public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
var parts = await content.ReadAsMultipartAsync();
var obj = Activator.CreateInstance(type);
var propertiesFromObj = obj.GetType().GetRuntimeProperties().ToList();
// *****
// * Populate obj using FormUrlEncodedJson.Parse()? How do I do this?
// *****
foreach (var property in propertiesFromObj.Where(x => x.PropertyType == typeof(AttachedDocument)))
{
var file = parts.Contents.FirstOrDefault(x => x.Headers.ContentDisposition.Name.Contains(property.Name));
if (file == null || file.Headers.ContentLength <= 0) continue;
try
{
var fileModel = new AttachedDocument()
{
ServerFilePath = ReadToTempFile(file.ReadAsStreamAsync().Result),
};
property.SetValue(obj, fileModel);
}
catch (Exception e)
{
// TODO: proper error handling
}
}
return obj;
}
/// <summary>
/// Reads a file from the stream and writes it to a temporary directory
/// </summary>
/// <param name="input"></param>
/// <returns>The path of the written temporary file</returns>
private string ReadToTempFile(Stream input)
{
var fileName = Path.GetTempFileName();
var fileInfo = new FileInfo(fileName);
fileInfo.Attributes = FileAttributes.Temporary;
var buffer = new byte[16 * 1024];
using (var writer = File.OpenWrite(fileName))
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
writer.Write(buffer, 0, read);
}
}
return fileName;
}
}
EDIT: after stewing on this for way too many hours, I've come to the conclusion that what I want to do is basically impossible. After talking to my boss, we've decided the best alternative is to make a second controller that accepts a file and then associates it to the rest of the form data, and put the onus on the front-end developers to do much more work to support that scenario.
I've extremely disappointed in the designers of Web API for making such a common use-case so difficult (if at all possible!) to pull off.
It actually does support MultiPart/FormPost data:
It's all about using the HttpContext of the Web API controller, and on the request you will have the files collection filled, and when data is being posted as well, you can access the data.
Below is an example that I use to upload a profile picture and the data object to go with it:
[Route("UploadUserImage", Name = "UploadUserImage")]
[HttpPost]
public async Task<dynamic> PostUploadUserImage(UserInfo userInformation)
{
foreach (string fileKey in HttpContext.Current.Request.Files.Keys)
{
HttpPostedFile file = HttpContext.Current.Request.Files[fileKey];
if (file.ContentLength <= 0)
continue; //Skip unused file controls.
//The resizing settings can specify any of 30 commands.. See http://imageresizing.net for details.
//Destination paths can have variables like <guid> and <ext>, or
//even a santizied version of the original filename, like <filename:A-Za-z0-9>
ImageResizer.ImageJob i = new ImageResizer.ImageJob(file, "~/image-uploads/<guid>.<ext>", new ImageResizer.ResizeSettings(
"width=2000;height=2000;format=jpg;mode=max"));
i.CreateParentDirectory = true; //Auto-create the uploads directory.
i.Build();
var fileNameArray = i.FinalPath.Split(#"\".ToCharArray());
var fileName = fileNameArray[fileNameArray.Length - 1];
userInformation.profilePictureUrl = String.Format("/services/image-uploads/{0}",fileName);
return userInformation;
}
return null;
}

Sharing variable using MemoryMappedFile gives error

I need to share a variable value from App "A" to different applications on same system. I need to use only MemoryMappedFiles as per requirement. I created another simple App "B" which reads value of shared variable from App A.
But App "B" gives error
Unable to find the specified file.
Sample App A and B written in C# using VS 2012 :
On Button click event of app A to share variable Name :
private void button1_Click(object sender, EventArgs e)
{
string Name = txtName.Text.ToString();
int howManyBytes = Name.Length * sizeof(Char) + 4;
label1.Text = howManyBytes.ToString();
using (var MyText = MemoryMappedFile.CreateOrOpen("MyGlobalData", howManyBytes, MemoryMappedFileAccess.ReadWrite))
{
byte[] array1 = new byte[howManyBytes];
array1 = GetBytes(Name);
using (var accessor = MyText.CreateViewAccessor(0, array1.Length))
{
accessor.WriteArray(0, array1, 0, array1.Length);
}
}
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
On Button click event of app B to read shared variable MyGlobalData :
try
{
using (var mmf = MemoryMappedFile.OpenExisting("MyGlobalData"))
{
using (var accessor = mmf.CreateViewAccessor(0, 34))
{
byte[] array1 = new byte[34];
accessor.ReadArray(0, array1, 0, array1.Length);
string result = System.Text.Encoding.UTF8.GetString(array1);
txtName.Text = result;
}
}
}
catch (Exception ex)
{
MessageBox.Show(" Error :- " + ex.Message.ToString());
}
When trying to read the shared variable from App B it gives error
Unable to find the specified file
Do i need to write variable value in txt file and then share it ?
Memory mapped files are two types
Persisted memory mapped file
Non persisted memory mapped file
You're creating Non persisted memory mapped file, so when the last process to close then handle of the MMF, it will be destroyed. You're closing the handle by calling Dispose on it through using statement, and thus MMF is destroyed.
You either need to keep the MMF open, or use Persisted memory mapped file. To keep the MMF open, just don't dispose it.
For more information

Get filename while downloading it

We are providing files that are saved in our database and the only way to retrieve them is by going by their id as in:
www.AwesomeURL.com/AwesomeSite.aspx?requestedFileId=23
Everything is working file as I am using the WebClient Class.
There's only one issue that I am facing:
How can I get the real filename?
My code looks like this atm:
WebClient client = new WebClient ();
string url = "www.AwesomeURL.com/AwesomeSite.aspx?requestedFileId=23";
client.DownloadFile(url, "IDontKnowHowToGetTheRealFileNameHere.txt");
All I know is the id.
This does not happen when I try accessing url from the browser where it get's the proper name => DownloadedFile.xls.
What's the proper way to get the correct response?
I had the same problem, and I found this class: System.Net.Mime.ContentDisposition.
using (WebClient client = new WebClient()){
client.OpenRead(url);
string header_contentDisposition = client.ResponseHeaders["content-disposition"];
string filename = new ContentDisposition(header_contentDisposition).FileName;
...do stuff...
}
The class documentation suggests it's intended for email attachments, but it works fine on the server I used to test, and it's really nice to avoid the parsing.
Here is the full code required, assuming the server has applied content-disposition header:
using (WebClient client = new WebClient())
{
using (Stream rawStream = client.OpenRead(url))
{
string fileName = string.Empty;
string contentDisposition = client.ResponseHeaders["content-disposition"];
if (!string.IsNullOrEmpty(contentDisposition))
{
string lookFor = "filename=";
int index = contentDisposition.IndexOf(lookFor, StringComparison.CurrentCultureIgnoreCase);
if (index >= 0)
fileName = contentDisposition.Substring(index + lookFor.Length);
}
if (fileName.Length > 0)
{
using (StreamReader reader = new StreamReader(rawStream))
{
File.WriteAllText(Server.MapPath(fileName), reader.ReadToEnd());
reader.Close();
}
}
rawStream.Close();
}
}
If the server did not set up this header, try debugging and see what ResponseHeaders you do have, one of them will probably contain the name you desire. If the browser show the name, it must come from somewhere.. :)
You need to look at the content-disposition header, via:
string disposition = client.ResponseHeaders["content-disposition"];
a typical example would be:
"attachment; filename=IDontKnowHowToGetTheRealFileNameHere.txt"
I achieve this with the code of wst.
Here is the full code to download the url file in c:\temp folder
public static void DownloadFile(string url)
{
using (WebClient client = new WebClient())
{
client.OpenRead(url);
string header_contentDisposition = client.ResponseHeaders["content-disposition"];
string filename = new ContentDisposition(header_contentDisposition).FileName;
//Start the download and copy the file to the destinationFolder
client.DownloadFile(new Uri(url), #"c:\temp\" + filename);
}
}
You can use HTTP content-disposition header to suggest filenames for the content you are providing:
Content-Disposition: attachment; filename=downloadedfile.xls;
So, in your AwesomeSite.aspx script, you would set the content-disposition header. In your WebClient class you would retrieve that header to save the file as suggested by your AwesomeSite site.
Although the solution proposed by Shadow Wizard works well for text files, I needed to support downloading binary files, such as pictures and executables, in my application.
Here is a small extension to WebClient that does the trick. Download is asynchronous. Also default value for file name is required, because we don't really know if the server would send all the right headers.
static class WebClientExtensions
{
public static async Task<string> DownloadFileToDirectory(this WebClient client, string address, string directory, string defaultFileName)
{
if (!Directory.Exists(directory))
throw new DirectoryNotFoundException("Downloads directory must exist");
string filePath = null;
using (var stream = await client.OpenReadTaskAsync(address))
{
var fileName = TryGetFileNameFromHeaders(client);
if (string.IsNullOrWhiteSpace(fileName))
fileName = defaultFileName;
filePath = Path.Combine(directory, fileName);
await WriteStreamToFile(stream, filePath);
}
return filePath;
}
private static string TryGetFileNameFromHeaders(WebClient client)
{
// content-disposition might contain the suggested file name, typically same as origiinal name on the server
// Originally content-disposition is for email attachments, but web servers also use it.
string contentDisposition = client.ResponseHeaders["content-disposition"];
return string.IsNullOrWhiteSpace(contentDisposition) ?
null :
new ContentDisposition(contentDisposition).FileName;
}
private static async Task WriteStreamToFile(Stream stream, string filePath)
{
// Code below will throw generously, e. g. when we don't have write access, or run out of disk space
using (var outStream = new FileStream(filePath, FileMode.CreateNew))
{
var buffer = new byte[8192];
while (true)
{
int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
break;
// Could use async variant here as well. Probably helpful when downloading to a slow network share or tape. Not my use case.
outStream.Write(buffer, 0, bytesRead);
}
}
}
}
Ok, my turn.
I had a few things in mind when I tried to "download the file":
Use only HttpClient. I had a couple of extension methods over it, and it wasn't desirable to create other extensions for WebClient.
It was mandatory for me also to get a File name.
I had to write the result to MemoryStream but not FileStream.
Solution
So, for me, it turned out to be this code:
// assuming that httpClient created already (including the Authentication cumbersome)
var response = await httpClient.GetAsync(absoluteURL); // call the external API
// reading file name from HTTP headers
var fileName = response.Content.Headers.ContentDisposition.FileNameStar; // also available to read from ".FileName"
// reading file as a byte array
var fileBiteArr = await response.Content
.ReadAsByteArrayAsync()
.ConfigureAwait(false);
var memoryStream = new MemoryStream(fileBiteArr); // memory streamed file
Test
To test that the Stream contains what we have, we can check it by converting it to file:
// getting the "Downloads" folder location, can be anything else
string pathUser = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string downloadPath = Path.Combine(pathUser, "Downloads\\");
using (FileStream file =
new FileStream(
$"{downloadPath}/file.pdf",
FileMode.Create,
FileAccess.Write))
{
byte[] bytes = new byte[memoryStream .Length];
memoryStream.Read(bytes, 0, (int)memoryStream.Length);
file.Write(bytes, 0, bytes.Length);
memoryStream.Close();
}

Read embedded file from assembly

I have to pass the path of a config file to a framework method (Gurok SmartInspect). The config file is an embedded resource of the assembly. Currently I read the file from the assembly and store it outside and then pass the pathName. Is there a better / less complicated way to achieve this goal, without copying the file?
private static void ConfigLogger()
{
const string embeddedFileName = "xxx.SmartInspect.properties";
const string configFileName = "SmartInspect.properties";
ExtractFileFromAssembly(embeddedFileName, configFileName);
SiAuto.Si.LoadConfiguration(configFileName);
}
private static void ExtractFileFromAssembly(string assemblyFileName, string configFileName)
{
using (Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(assemblyFileName) )
{
byte[] buffer = new byte[s.Length];
int read = s.Read(buffer, 0, (int)s.Length);
using (FileStream fs = new FileStream(configFileName, FileMode.Create))
{
fs.Write(buffer, 0, buffer.Length);
}
}
}
If the only way that Gurok SmartInspect reads configuration information is from a file that you pass it a path to and you've decided to embed that file in your assembly, then yes, your method is fine. You might want to consider adding some exception handling but otherwise I see no problem with this.

Categories

Resources