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.
Related
I have an old MVC 4 project that uses ASP.NET Resources in Razor views for localization.
I.e in a Razor view you may see
Views/Register.cshtml:
#Resource(() => Local.TermsAndConditions
This will go off and fine
Resources/Register.resx
And find the 'TermsAndConditions' parameter with the correct culture.
Now I don't actually know how all of this works, I've never worked on a multi-lingual application before, but I know that these resx files don't even have the correct information - what actually happens is somehow we fetch these from what looks like a complicated set of SQL tables in the database, using a built ResourceCache class.
I am trying to re-write the front-end using React, but am struggling with how to keep the localization - there are hundreds of entries and I am pulling my hair out a little here.
The only solution I can think of, is to manually find all the keys that would be required to lookup at the top of the view, and send these off to a custom API that will process these values for me, but feel like that may cause a large overhead on my application!
Any ideas?
So I solved this by creating a simple API method
List<string, string> LocaliseStrings (List<string> keys)
{
// get UI culture
// look up translated string
// add to return list in KVP
}
This would be called on every front-end page before anything else, and return the strings necessary
Some background on this question. I've built a webapp inside of SharePoint that walks a user through a series of forms. Each form is a ASP.NET page with a number of SharePoint and custom controls. As part of a new feature request(details not relevant here), I need to know what fields are on each form. I'm planning to maintain this data inside of a SharePoint list that other pieces of my code will access programatically.
Rather than maintaining this list by hand, I'd like to populate it in my deployment scripts (written in C#). What I'm hoping is possible is the create a new Page object for each one of my Pages, and then walk through it's Controls collection using some extension methods I've already built to find out which fields are on each form. Is there a good way to instantiate the Page object in this context? To be completely specific, the deployment code runs inside of a SharePoint event receiver, but if you're not familiar with SharePoint, it would be similar trying to accomplish the same thing inside of a console app.
Well, as long as you have access to your web application's assembly you can make the following using Reflection:
1) Load the assembly into memory.
Assembly asm = Assembly.LoadFrom(#"Your assembly path");
2) Query the types for each one of your pages:
var types = asm.GetTypes();
3) For each of your Type instances, get the constructor, invoke it, get the page's instance and then call your Helper methods.
t = types[0];
t.GetConstructor(new Type[] { });
t.GetMethod("Your Method").Invoke(t, object[] {});
I created an asp.net Server control that derives from a LinkButton, and renders a small javascript function to the page.
I want to use this control many times on the page, but just want the javascript to be rendered once on the page. On the other hand, I rather not manually add it in a js file, because i don't want to have a chance of forgetting to add the js file in the future.
What will be the best way to go about doing this ?
Preventing duplication in client scripts
Use a registration method such as Page.ClientScript.RegisterClientScriptBlock(..). There are a couple of overloads but they all work in a similar fashion. It's smart enough to render the script only once no matter from how many control instances it's issued.
Microsoft remarks in the MSDN documentation:
A client script is uniquely identified
by its key and its type. Scripts with
the same key and type are considered
duplicates. Only one script with a
given type and key pair can be
registered with the page. Attempting
to register a script that is already
registered does not create a duplicate
of the script.
The MSDN docs also contain sample code such as this:
// Check to see if the client script is already registered.
if (!cs.IsClientScriptBlockRegistered(cstype, csname2))
{
StringBuilder cstext2 = new StringBuilder();
cstext2.Append("<script type=text/javascript> function DoClick() {");
cstext2.Append("Form1.Message.value='Text from client script.'} </");
cstext2.Append("script>");
cs.RegisterClientScriptBlock(cstype, csname2, cstext2.ToString(), false);
}
Other similar registration methods
Different methods can be used to register your client script in different ways - see each of the ClientScriptManager.RegisterClientScript*(..) methods in MSDN for more detail about each. They're all built to prevent duplication in the rendered page.
This gives you the freedom to output scripts at the control level without worrying or having to track or count scripts.
Edit:
The ClientScriptManager instance is accessed through the Page.ClientScript property.
You can use the Page.RegisterClientScriptBlock method.
Here is an example from the MSDN:
if (!this.IsClientScriptBlockRegistered("clientScript"))
{
// Form the script that is to be registered at client side.
String scriptString = "<script language=\"JavaScript\"> function DoClick() {";
scriptString += "myForm.show.value='Welcome to Microsoft .NET'}<";
scriptString += "/";
scriptString += "script>";
this.RegisterClientScriptBlock("clientScript", scriptString);
}
HTH
Any way to reference a script on a CDN and not have it duplicated multiple times? Or can I just not worry about it since it's just a pointer anyway and the browser is (?) smart enough not to load the same library twice?
In other words, suppose I want the following code inserted from a server control:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
If I use a RegisterClientScriptBlock I can use the IsClientScriptBlockRegistered method to not have the server control load it multiple times. But, the preceding code is likely to have been put on the page anyway by either another (different) server control or by the developer who wants to use jQuery for something outside of the server control.
How do I get the server control to not load the script if the developer already loaded it?
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.
I've been given a prototype/mockup of a grid written in html and javascript (via ExtJS) that I now need to implement within an ASP.net web application. Does anyone have any pointers as to how to pass data to the grid (to a GroupingStore, specifically).
I'd rather not have a proliferation of web services or helper pages returning XML/JSON so if there's a way to use Client callbacks or Page Methods (Can't you tell I'm not particularly familiar with either - buzzword bingo!) or somesuch, that would be preferred.
Please, no recommendations that I use jQuery, the built-in ASP.net grid, or any other UI framework. The use of the ExtJS grid has been mandated by the powers that be, so that's the grid I'm using, for better or worse :)
I believe a service that simply returns json structures for your pages is the best option, nicely abstracted and reusable across the application rather than page methods.
Here's a low tech solution. It doesn't require use of web services or any other additional technologies.
Step 1
Have an ASPX page that takes one paramter, and invoked like this:
http://mysite.com/query.aspx?sql=select * from orders where status = 'open'
Step 2
In the code behind, do something like this
void Page_Load(object sender, EventArgs e)
{
Response.ContentType="text/json";
DataTable contents = ExecuteDataTable(Request["sql"]);
Response.Write( JRockSerialize( contents ) );
Response.End();
}
You can use JRock for serializing a data table to JSON.
IMHO this gives the cleanest JSON.
So that's getting DataTable to JSON sorted...
WARNING: This is obviously a simplistic example. You shouldn't pass SQL on the query string as it is not secure (your could use named queries and parameters instead).
Step 3
In your ExtJS code, create a grid with Json datastore as shown in this Ext example. Set the data store url: to that of your query.aspx page with appropriate query string parameters.
You'll also need to set the columns up for the grid, again shown in the ExtJs example.
Alternatively...
I was really impressed when I looked at the Coolite samples recently. They are an ExtJS partner and provide a good ASP.NET & ExtJS experience. And no, I don't work for them :) I haven't tried their grid, but it might be painless (at a price).