Azure - How to access content files of WorkerRole? - c#

I'm writing a worker role for sending emails. It has some email template html files with build action = content and copy to output = Copy Always
How can i access those files from the code of the WorkerRole?
I don't want to store those files in a blob because i need to upload this service as soon as possible and i have to be able to edit those email template easily without wiring up extra code for that.
EDIT:
Guys i'm talking about Azure. This doesn't work with the regular method of loading the Folder of the current running assembly because that would give you the Azure host process which is located in a different place.

I figured it out - here's how to do it:
Path.Combine(Environment.GetEnvironmentVariable("RoleRoot") + #"\", #"approot\FileTemplates\");

Having a build action - content does not embed the file into the .dll, it is deployed into your assembly directory (usually \bin), then in the same folder structure that you have the template in. That was confusing to write, so here is an example:
Project Directory
-Templates
-EmailTemplateA
When complied and deployed, EmailTemplateA would be in the following location: \bin\Templates\EmailTemplateA
Now that we know where it is at, we need to use it. Below is a code snippet that would load a template, replace some values and then send your email
public void SendRegistrationConfirmation(string toAddress, string confirmUrl)
{
const string subject = "Your Registration";
//load the template
var template = File.OpenText(AssemblyDirectory + " \\Templates\\NewProgramRegistration.Template").ReadToEnd();
//replace content in the template
//We have this #URL# string in the places we want to actually put the URL
var emailContent = template.Replace("#URL#", confirmUrl);
//Just a helper that actually sends the email, configures the server, etc
this.SendEmail(toAddress, subject, emailContent);
}

You could store your templates in Local Storage:
http://convective.wordpress.com/2009/05/09/local-storage-on-windows-azure/

You should reconsider you design.
- as mentioned above, you can use Local Storage (you would need to copy the files there first) and then you can use the System.IO .NET API to manipulate the files
The problem with this is (as you said you are making changes)
- what if you horizontally scale, now you have individual worker roles that have their own local copy of the "template". You mention not wanting to use blob storage, but that should be an option since it can act as a central/persisted repository for your templates. And you can copy them locally of course as needed.
Another option is to use SQL Azure DB. Something like templates, should be super fast on it that multiple roles can share.

Related

Image src pointing on a file outside my project folder in WEB FORM

I'm looking to do this exactly :
set src property in view to a url outside of the MVC3 project
Fine but in web form ?
I tried simply putting the path as a string into the src of the image :
<asp:Image ID="imgInside" runat="server" src="\\serverName.com\dfs$\APPL-ADM\FichiersDev\MandatsInfo\SAR220-2020_1.jpg" >
Obviously not working, so I made src pointe on this function I wrote like so :
<asp:Image runat="server" Width="160px" src='<%# getImage(Container.DataItem as MandatMobile.DAL.MandatsEcoleCC_Result) %>' ></asp:Image>
In back end C# :
protected Byte[] getImage(MandatsEcoleCC_Result p)
{
using (MandatsDatas db = new MandatsDatas())
{
GROUPE_ARTICLE g = db.GROUPE_ARTICLE.First(t => t.ID_GROUPE == p.ID_GROUPE);
if (string.IsNullOrWhiteSpace(g.image))
return null;
FileStream fs = null;
try
{
fs = new FileStream(#"\\serverName.com\dfs$\APPL-ADM\FichiersDev\MandatsInfo\" + g.MANDAT.NO_MANDAT + g.image, FileMode.Open, FileAccess.Read);
}
catch
{
}
BinaryReader br = new BinaryReader(fs);
return br.ReadBytes((int)fs.Length);
}
}
Still not working, I've been searching but I just can't figure it out and I'm stuck trying all sorts of non-sens.
Well, you confusing two things:
Code behind:
Anytime you run code that uses a file, then you writing 100% server side code. As such any file path is a proper windows FULL qualified path name. It has ZERO ZERO to do with web URL's.
Read the above a dozen times. Your code does not use URL path names - end of story.
Web site:
Anytime you reference a file, picture, script files or anything? You are and MUST use a URL based on the path names of the web site, and more so path names that resolve to the folders that represent the site.
root:
\Pictures (say a folder in the web site folder list with pictures.
So, a src, or ANY URL in the web site? They do NOT use windows path names like code behind.
So, if there is a cat.png picture in folder pictures? When your URL will be this:
www.mywebsite.com/Pictures/cat.png
If you write code to read/load/see/use that cat.png picture? Then you convert in code from that extenral URL to a full qualifed standard windows path name (with back slaches).
So, in code behind if you want to read, or do somthing with the above file?
You use
dim strFile as string
strFile = Server.MapPath("www.mywebsite.com/Pictures/cat.png")
map path will now return a full qualified windows server path
eg:
c:\inetpub\wwwrootmysite\Pictures\cat.png
Ok, so now we realize that to use a VALID link to pictures on teh web site, we MUST use a valid URL.
So, what happens if say we have a network connected HUGE massive say SAN drive or some other huge server on the network that has huge storage, and has our pictures in that site?
Say:
\SANSERVER\WebPictures\cat.png
Well, obviosity that file folder can't be used in a URL. ONLY URL's in the web folder path name can be used. And this is a good thing. Since when I go to www.amazon.com it is a VERY good thing I can't type in a URL to get at their intenral accouting files server and steal all the credit card information of all customers.
So, now, how can I get at that cat.png, and turn it into a valid URL?
There are two ways:
One:
You make the decision to expose and INCLUDE the above path name as part of the web site. This is typical done with what is called a virutal folder. You need IIS, and during development with IIS + Visual Studio, it is a "pain" to setup such path names. But if you have full version of IIS, then you can add the virutal folder to the web site though the IIS user interface tools.
So, you add a virutal folder called MyPictures, and it will be mapped to:
\SANSERVER\WebPictures\cat.png
So, now the web site URL becomes:
www.mycoolsite.com/MyPictures/cat.png
And in code if you do a server.map path, the above url will return this:
\SANSERVER\WebPictures\cat.png
Ok, next issue:
I don't want to expose that other folder to the web site. I don't want a valid URL, and I don't even want users to be able to type in say this:
www.mycoolsite.com/MyPictures/doggie.png
So, if you DO expose another folder or add a folder to the web site hiarchy, then users ARE FREE to type in a URL that will resolve to that other folder (but you are assumed to have added a virtual folder to the web site).
Now, with a valid URL resolution, then you can place markup code on teh web site, and provide valid full URL path names to the picture or whatever for the web site.
However, lets say for reason of security, I do NOT want that other server to be exposed to as a URL?
Well, it it is NOT exposed as a valid web URL folder, then you can NOT put in a valid URL - it that's simple.
However, that don't mean the code behind can't read/load/open that file on the server. In fact the web site code behind can often read any file on the server, and in fact read any file anyplace on the network that the web server is running. And as noted, code behind does not use URL
s, and does not use "forward" "/" for the file - but a plan jane old fashting fully qualfied windows path name.
Since the code behind can darn near read any file and do anything it wants?
Ok, then how can we get the code behind to dish out a file, or send that file to the web site?
Two simple ways:
Your code behind could read the cat.png file, and copy it to a folder that is part of the web server folder layout. Once one, then you can provide a valid URL. However, with a huge picture library, that would be pain full.
And in some cases the picture might come from a database row(s) that store pictures, and once again no valid path name exists for the web site.
So, what you can do is read the file in code behind and then "stream" the data directly to the web site.
When you steam contents from code behind, then you don't care nor even require a valid URL, because the code behind is pumping out the object data (in this case a picture cat.png) directly to the web browser. So this is often done because your pictures don't even exist in a file, or in fact it not practical to include that folder in the web site folder list for reasons of security.
As noted, if this was/is just a folder of pictures OUTSIDE of the folders for the web site? Well then 99% of the time, then adding a mapped folder (a virtual folder) to the web site that points to the picture hard drive is common done, and is practical.
however, you might have a HUGE library of pictures on a big file server, and you have a database that has key words for searching the pictures, and the database row stores a valid path name to the hard drive/server that has all the pictures in a Hodge podge folder hierarchy that is not practical to expose as web based urls.
So, how to stream a file?
You code is close, but you need to include additional information. And unfortantly the server can't stream the file down as 100% binary format.
So, say we drag + drop a image control onto the form. You have this:
<asp:Image ID="Image1" runat="server" />
So, now in code behind to stream + set the picture to a picture on the hard drive?
You can use this:
Dim strFile As String = "c:\Test4\pcards.bmp"
Me.Image1.ImageUrl = Gimage2(strFile)
Now of course the URL path name to the above Test4 folder does not exist.
Gimage2 - it just converts the file as a byte array, and then to a string coded as base64.
Function Gimage2(strPath As String) As String
Dim PicData As Byte() = Nothing
PicData = File.ReadAllBytes(strPath)
Dim ContentType As String = "image/" & Path.GetExtension(strPath)
Return "data:" & ContentType & ";base64," & Convert.ToBase64String(PicData, 0, PicData.Length)
End Function
So I spent some time with a long post. The reason is you attempted to use a URL with standard windows back slashes, and that means in your mind, you are using the concept of a windows full path name and MAJOR confusing that with a URL path name. Failure to make this distingishing will cause you years of pain and suffering. You must have BEYOND CRYSTAL clear this concpet of a URL and that of a file name in code behind. They are two VERY different things.
If that addtional folder is "ok" to expose to the web site? Then create a Virtural folder.
That means:
wwww.mycoolsite.com/MyPictures/dog.png
Could in fact point to ANY mapped folder on your server. And this means the web server will require permisions to that folder, and in most cases thus a user (or your code) can type in and use a full web path name to the picture.
However, as noted, for pdf documents and many other types of files, then it is out of the question to have a valid URL and a mapped folder. So you can use the 100% file based approach as per above, and read the file as bytes, and then stream + output the file to the browser.
You can even do a response.write and pump out the file directly to the browser, but then again you don't have much control as to where it will be. Do realize that pumping out a string as base 64 data as per above can and will cause some bloat and expansion in the size of the string sent to be rendered as a picture. So for a simple image - sure that's ok. But for a larger high quality high resolution image, then of course I don't recommend you send the picture as a base64 string due to the expansion that string will result in.
I ended up putting a fonction in another MVC project that works correctly to retrieve images.
So my src path point on an URL instead of a file on a server path.
src='https://NameOf_MVC_webSite.csdn.qc.ca/imageBank/ForMandat?name=' + (Container.DataItem as MandatMobile.DAL.MandatsEcoleCC_Result).image
Dirty solution using another deployed app that has a (better / easy to use / functional) framework
But this is not an "OK" solution

Better solution to store data for dll assembly

I'm developing a dll that is supposed to be commonly used (in nuget for example). Simple description: my DLL simplifies message exchange with a particular service. It allows to send a request, then retrieve a response. Service is asynchronous and it can create a response in a hour or a day after accepting a request, so after making a request my dll calls service every few minutes to check out for response. The problem is that the app that uses the dll can be restarted therefore storing a request queue in memory isn't a good option (I don't want to lose info about requests). Neither is serializing it to file, because I can't know for sure where my dll will be used - it could be pc app, mvc. My main options is: serialize to file, but give an option to set a address where to place serialized files via web/app.config or make a user to think about it. But maybe there is some better solution about how to store requests queue?
I would put theses type of configuration or data files in a subfolder to the %appdata% folder. You will have write access to files in this folder and the documentation is extensive. Read more here.
in C# you can easily get this folder using:
var appdata = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
Or use Program Data:
var programdata = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

Delete and upload files into Azure webapp local storage programatically

I've deployed a website into Azure and i want to access programaticaly this path : "D:\home\site\app" from a c# desktop application and delete all files and upload new ones programatically.
i have searched and found many ways but all are for AzureStorage or using Kudu consol or FTP while what i realy want is to access the local storage where the website is deployed programatiacally, and make some edits on files programatically.
Sure thing, the Site Control Manager (Kudu) has an API for that, the VFS API:
https://github.com/projectkudu/kudu/wiki/REST-API#vfs
You can use either of these for authentication:
A Bearer token that you obtain from the STS (reference implementation in ARMClient)
Site-level credentials (the long ugly ones under your Web App → Properties)
Git/FTP credentials (subscription level)
Sample usage (using site-level credentials):
# Line breaks brutally used to improve readability
# /api/vfs/ is d:\home
# Append path as necessary, i.e. /api/vfs/site/app
$ curl -k https://$are-we-eating-too-much-garlic-as-a-people:6sujXXX
XXXXXXq7Zc#are-we-eating-too-much-garlic-as-a-people.scm.azurewebsites.net
/api/vfs/site/wwwroot/ill-grab-this-file-over-vfs-api.txt
There, i did it.
I'm assuming here that you want to do all that from the outside world - since you don't clearly state otherwise.
Well, in my azure code. my task was to save a excel file and upload its contents to SQL server.
I used this plain and simple to access home site.
string fileToSave = string.Format("{0}\\{1}", HostingEnvironment.MapPath(#"~\Temp"), FileUpload.FileName);
if (!Directory.Exists(HostingEnvironment.MapPath(#"~\Temp")))
Directory.CreateDirectory(HostingEnvironment.MapPath(#"~\Temp"));
FileUpload.PostedFile.SaveAs(fileToSave);
you could use something like this to delete and save a new file or other I/O operations.

how do I access a folder on the shared hosting space?

I am trying to upload image files to the server and it gives me an error
"System.UnauthorizedAccessException: Access to the path 'D:\Hosting\234344\html\Testingfiles\upload\813.jpg' is denied.at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)"
in the HttpHandler I have :
HttpPostedFile file = context.Request.Files["Filedata"];
string usr_id = context.Request.Form["usr_id"];// gets the JSON data from the request
string strPath = context.Server.MapPath(("/Testingfiles/upload/") + file.FileName);
string ext = Path.GetExtension(strPath);
if (ext.Equals(".jpg") || ext.Equals(".jpeg") || ext.Equals(".png"))
{
file.SaveAs(strPath);
context.Response.Write("Image uploaded successfully");
}
what am i doing wrong here?
The error message says it all. You don't have write access to that folder.
You will need to ask your hosting provider to assign write rights to that folder for the ASP .NET identity.
Also, consider if you can use a folder below ~/App_Data. This is by convention the place to store files that needs write access in ASP .NET, so many hosting providers will allow writes to this folder by default (but you would need to check yourself for your specific host to be sure).
You should try writing to ~/App_Data/ to see if that works. If it does then its just because you haven't given asp.net write permission to the /TestingFiles/Uploads/ folder.
If your control panel has Plesk on it then you can sort this out yourself by going to the FileManager and clicking the permissions button. If you look at your App_Data file permissions for reference, the actual username that you need to add will vary depending on your domain name with plesk.
Other hosting control panels may allow you to do it in different ways.
If you can't find it then you should ask your host how you set up file permissions or look in their knowledge base.
If your control panel has Plesk on it then you can sort this out yourself by going to the FileManager and clicking the permissions button.
I fixed this error by allowing IIS users full access to upload folder. No need to use App_Data folder
For Plesk 12.0 only:
No need to use App Data folder. You just have to give full control to your Application pool group IWPG(username). It will surely work. I searched for many hours and this solution worked for me .
Hope It works for others too.

how to create folder on server from code in c#?

Is there any way to show user popup to give the name to create folder
And with that if he does not want to create folder then he should be shown the list of folders to which he want to save the file
Is it proper way that I create a popup with javascript with the list of folders on my server and put a textbox and button to save the new and in code we will create directory in code passed with textbox?
string pathToCreate = "~/UserFolders/" + TextBox1.Text;
if(Directory.Exists(Server.MapPath(pathToCreate))
{
//In here, start looping and modify the path to create to add a number
//until you get the value needed
}
//Now you know it is ok, create it
Directory.CreateDirectory(Server.MapPath(pathToCreate));
string targetPath = Server.MapPath("FolderName"); //with complete path
if (!System.IO.Directory.Exists(targetPath))
{
System.IO.Directory.CreateDirectory(targetPath);
fileToUpload.PostedFile.SaveAs(targetPath + ImageFileName);
}
else
{
fileToUpload.PostedFile.SaveAs(targetPath + ImageFileName);
}
As I mentioned by commenting that Functionality like SaveFileDialog is only possible in Windows Forms application, you cannot do this in asp.net
The alternatives in asp.net are difficult however as an alternate there is a third party editor available on the web called CKEditor 3.x Developer's Guide.
You can use File Browser (Uploader) for the purpose you want to achieve.
to create folder :
System.IO.Directory.CreateDirectory(newPath);//newpath is your folder creating path
If you are developing web applications (I can see you have tagged your question as asp.net), you do not need to worry about the pop up window. You just send the file through the Response and the download window will be shown by the browser.
Using the Example given in How to Create a Folder or File You can create a folder, but in asp.net you can not Use open file dialog or save file dialog functionalities, this will work only in C# Windows forms application.
Web applications and the HTTP protocol do not support direct manipulation of the server-side file system. In fact, that would be a dangerous idea.
It sounds like you have a base folder somewhere on the web server where you want users to be able to upload files, with some user control over subfolders and location of the uploaded file. I would suggest dong this by presenting the file system in a tree view or a list of links (where the links let you navigate up/down the folder tree). Combine this with a file input and you've got yourself a solution. HOWEVER, be very careful to control and cleanse the specified file name for the uploaded file. There are many combinations (such as utilizing "..") that can allow the user to hack into unwanted file locations on your server.

Categories

Resources