detect if an ASCX/ASPX is running in SharePoint? - asp.net

We have a set of code that is going to be used in both standalone ASP.NET and SharePoint. I'm wondering if there's any legitimate way to write conditional code in the CS file to detect whether SharePoint is present?
It needs to be able to run in or before OnPreInit, because based on this decision we'll be switching the MasterPageFile attribute, and that needs to be done early in the page lifecycle.
I suppose I can do something like checking for the existence of a "~/layouts" directory, etc. but there must be a better way to do this. And besides, who knows - for compatibility reasons (location of images, etc) we might actually adopt the SharePoint directory structure in the ASP.NET standalone mode.
It's okay to require the Microsoft.SharePoint.DLL even if it goes mostly unused when running standalone.
Thanks!

Since you are allowed to reference Microsoft.SharePoint:
using Microsoft.SharePoint;
// ...
if (SPContext.Current == null)
// Not running in SharePoint
else
// Running in SharePoint
Edit -- alternate approach taking NullReferenceException into consideration:
bool runningInSharePoint = false;
try
{
if (SPContext.Current != null)
runningInSharePoint = true;
}
catch (NullReferenceException e)
{
// SharePoint is not present on the system
}
The above assumes that the exception you mentioned is thrown when accessing SPContext, not earlier.

I wonder if you are better off not including the SharePoint dll in your straight ASP.NET code.
If you partial/sub class the SharePoint bit and include two build targets, you should be able to tack on the extra code needed for SharePoint without turding up your ASP.NET build.

Related

Distinguish between SpecFlow and Unit Test assembly

I have written some code that analyzes a test DLL and extracts names of tests and which tags they have using reflection.
I originally wrote it to analyze SpecFlow DLLs, but it seems to work fine for Unit Test DLLs, with a few tweaks.
Both are using MSTest (VSTest.Console.exe)
I am wondering if anyone knows how I could distinguish one type of assembly from the other, so that I can use the same code to analyze either kind of assembly, without having to specify what kind it is.
Also, if anyone knows of an existing tool to do this (Extract lists of tests from DLLs), that would be great. I am kind of feeling like I must be re-inventing the wheel here...
Sample files
Specflow DLL
Unit Test DLL
(You probably need to right-click these and unblock to be able to load them)
TLDR: How do I detect, through code, which one of these DLLs is Specflow and which is Unit Tests?
Duh, it was actually quite simple
public static bool IsSpecflowDll(Assembly assembly)
{
var references = assembly.GetReferencedAssemblies();
foreach (var reference in references)
{
if (reference.Name == "TechTalk.SpecFlow")
{
return true;
}
}
return false;
}

Folder browsing in ASP.net

What I'm trying to do here is to allow my user to select a path in a data server on a network, so that I could generate a configuration file.
I hope to be able to replicate the function of OpenFileDialog() on my asp.net page. However this function does not exist on asp.net, and I do know that there is this control in asp.net call FileUpload. But what I required here, is just the path/directory for the folder. I do not require my files to be uploaded.
How can it be done?
Doing this in a web application is tricky. You would have to enumerate the folders on the server that you want to browse (presumably this is the same server that's running the web application), and then present that hierarchy to the user to select a folder. If it's not too big a hierarchy, you could just enumerate the whole bunch up front, and display it in a tree. If it's big for that, you could use an Ajax approach: select the top-level folder, then send an Ajax request to get the next level, and so on.
To enumerate the folders, you'll need to walk the filesystem yourself. See http://msdn.microsoft.com/en-us/library/dd997370(v=vs.100).aspx for one way.
No, there is no inbuilt control for this. It is not a normal requirement cause most site don't let their users see their file structures.
Building a user control that does this will be simple though.
I suggest using a TreeView asp.net control, attached to your datasource where you have listed the files.
This sample on binding a treeview should get you started.
You can populate your data using
var path = Server.MapPath("/");
var dirs = Directory.[EnumerateDirectories][2](path);
var files = Directory.[EnumerateFiles][3](path );
Finally to make it look like a dialog, you could use the jQuery UI dialog component.
The solution I have found is, this is just for anyone looking for answer:-
protected void browse_Click(object sender, EventArgs e)
{
Thread thdSyncRead = new Thread(new ThreadStart(openfolder));
thdSyncRead.SetApartmentState(ApartmentState.STA);
thdSyncRead.Start();
}
public void openfolder()
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
DialogResult result = fbd.ShowDialog();
string selectedfolder = fbd.SelectedPath;
string[] files = Directory.GetFiles(fbd.SelectedPath);
System.Windows.Forms.MessageBox.Show("Files found: " + files.Length.ToString(), "Message");
}
The asp.net site is a completely disconnected environment to your server. As other people have mentioned, to replicate an OpenFileDialog() you will need to look at the folder structure and present this to the user in the web/disconnected environment. In this case the user is abstracted from the actual file system... since this abstraction already occurs, it would be a good time to consider the route you're taking. It might be worth considering that a direct replication of the file system is not required, you could manage the "virtual" folder structure in the database with links/paths to files on disk are maintained there?

Override the Default ViewEngine to Look in Different Directories

I created an area in Visual Studio which automatically adds the appropriate bits in the "Areas" directory. I renamed this to "Modules" but now when i navigate to /{area}/{controller/{action} it still looks for the view within the /Areas/{area}/Views/{controller/{action} directory and not the /Modules/{area}/Views/{controller/{action} directory. I would also like to be able to override the view for specific themes. Therefore i was wondering how i could customise the default view engine to look for the view in the following locations aswell:
/Themes/Default/Views/{area}/{controller}/{action}.cshtml
/Modules/{area}/Views/{controller}/{action}.cshtml
I'd really appreciate it if someone could help.
Thanks
As ASP.NET MVC source code is available, it is easy to answer these kinds of questions by looking at the source. If you look at the WebFormViewEngine class you can see the locations listed and it will be easy for you to inherit from this and customise them.
However, not going with the code by convention approach is just going to make your life harder so I'd advise living with the default locations.
Here's the code incase anyone is interested:
public class CustomRazorViewEngine : RazorViewEngine {
public CustomRazorViewEngine()
: this(null) {
}
public CustomRazorViewEngine(IViewPageActivator viewPageActivator)
: base(viewPageActivator) {
AreaViewLocationFormats = new[] {
"~/Themes/Default/Views/{2}/{1}/{0}.cshtml",
"~/Themes/Default/Views/{2}/Shared/{0}.cshtml",
"~/Modules/{2}/Views/{1}/{0}.cshtml",
"~/Modules/{2}/Views/Shared/{0}.cshtml"
};
AreaMasterLocationFormats = new[] {
"~/Themes/Default/Views/{2}/{1}/{0}.cshtml",
"~/Themes/Default/Views/{2}/Shared/{0}.cshtml",
"~/Modules/{2}/Views/{1}/{0}.cshtml",
"~/Modules/{2}/Views/Shared/{0}.cshtml"
};
AreaPartialViewLocationFormats = new[] {
"~/Themes/Default/Views/{2}/{1}/{0}.cshtml",
"~/Themes/Default/Views/{2}/Shared/{0}.cshtml",
"~/Modules/{2}/Views/{1}/{0}.cshtml",
"~/Modules/{2}/Views/Shared/{0}.cshtml"
};
}
}
Now just place the following in the Application_Start event in the Global.asax.cs file:
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomRazorViewEngine());
Hope this helps.
The code you posted is very similar to what I wound up doing a few months ago.
I also have a preprocessing step (run on-demand or at compile time) which finds all of the .cshtml files in the site folder hierarchy and adds their relative paths to a table in the database. The site caches that data on startup. The custom view engine then searches that list for views, and only checks the disk when it finds a match.
This performs very, very well. Avoiding disk access will probably only help if you're running a very busy site. Even though disk access is very slow, it's typically not a performance bottleneck and ASP.NET performs its own intelligent caching.

Include ASP.NET pages from C#

In a typical web framework
func viewHomepage()
response.write(template.render("a string variable", ["an", "array"]))
is a fairly standard way of calling a templating engine and writing the output out.
Obviously the situation is reversed in ASP.net, since the templating engine sits in front of the code.
I am dealing with a legacy application that can't be rewritten. It's basically a 50 line xxx.aspx with a corresponding 20,000 LOC xxx.aspx.cs. What I want to do is write new "views" as separate ASP.net forms and controls and then include them back into the
xxx.aspx.cs.
Essentially instead of doing:
case "newfeature":
{
Response.Write("<table>");
...
Response.Write("</table>");
}
break;
I want to do
case "newfeature":
Response.Write(THEFUNCTIONIMLOOKINGFOR("newfeature.aspx"));
break;
That way there'll be some notion of modularity and it won't be reminiscent of a perl CGI script.
Show me a path to sanity pretty-please.
This can be done quite simply by calling the RenderControl method. You just need to pass it an HtmlTextWriter instance.
The technique is described here: 4GuysFromRolla.com "Emailing the Rendered Output of an ASP.NET Web Control"
There's also the MSDN Reference for the RenderControl method.

ASP.NET Localized web site -- updating on the fly

I think I have a solution to this, but is there a better way, or is this going to break on me?
I am constructing a localized web site using global/local resx files. It is a requirement that non-technical users can edit the strings and add new languages through the web app.
This seems easy enough -- I have a form to display strings and the changes are saved with code like this snippet:
string filename = MapPath("App_GlobalResources/strings.hu.resx");
XmlDocument xDoc = new XmlDocument();
XmlNode xNode;
xDoc.Load(filename);
xNode = xDoc.SelectSingleNode("//root/data[#name='PageTitle']/value");
xNode.InnerText = txtNewTitle.Text;
xDoc.Save(filename);
Is this going to cause problems on a busy site? If it causes a momentary delay for recompilation, that's no big deal. And realistically, this form won't see constant, heavy use. What does the community think?
I've used a similar method before for a very basic "CMS". The site wasn't massively used but it didn't cause me any problems.
I don't think changing a resx will cause a recycle.
We did something similar, but used a database to store the user modified values. We then provided a fallback mechanism to serve the overridden value of a localized key.
That said, I think your method should work fine.
Have you considered creating a Resource object? You would need to wrap your settings into a single object that all the client code would use. Something like:
public class GuiResources
{
public string PageTitle
{
get return _pageTitle;
}
// Fired once when the class is first created.
void LoadConfiguration()
{
// Load settings from config section
_pageTitle = // Value from config
}
}
You could make it a singleton or a provider, that way the object is loaded only one time. Also you could make it smart to look at the current thread to get the culture info so you know what language to return.
Then in your web.config file you can create a custom section and set restartOnExternalChanges="true". That way, your app will get the changed when they are made.

Resources