ASP.NET page or control marked as internal doesn't work and gives "inaccessible due to its protection level" error - asp.net

I know why this happens and I want to find a workaround it.
Example: a user control that exist in 2 assemblies, loaded at the same time.
namespace MyNamespace
{
internal class MyUserControl : UserControl
{
}
}
My situation - I want to be able to share user interface control between two web applications which are loaded at the same time in the same application pool. If my user interface class is marked public, then ASP.NET will not like it because it will be duplicated into memory ( CLR uses namespaces as full qualifier for class, and if the same class and namespace is met it more than one assembly, exception is thrown ). I do then mark the class as internal and of course I forget how UI compilation occurs, and I expect it to work. Of course it doesn't because ASP.NET compiles the UI into separate assembly which is dynamic and since I marked the class as internal, it is not visible to the main assembly...
The question that follows is: How can I make dynamic compiled assemblies that ASP.NET generates to view the main application assembly internals? It is very unfortunate that classes and methods I write into my UI controls must always be public! Has anyone met this obstacle in his daily work and found a workaround?
EDIT:
Precompilation is not possible here due to other circumstances.

You can share User Control markup between apps using a Virtual Path Provider (see
http://weblogs.asp.net/scottgu/archive/2005/11/27/431650.aspx and http://msdn.microsoft.com/en-us/library/system.web.hosting.virtualpathprovider.aspx).
You can pull the markup for the control from anywhere - SharePoint uses VPP to get markup from the database, and I use it in some projects to pull from a non-standard location on disk (which is shared between projects).

If your base class is internal, the derived class that ASP.NET generates at runtime will not be able to extend it.
However, I don't understand the issue that you're running into in the first place. Two distinct web applications will always run in different AppDomains (even if they're in the same app pool), and there should be no type conflicts between the AppDomains.
I probably need more details about what you are doing. e.g. what assembly are you compiling your base class into, and why does it end up in two different assemblies?

Related

Building old-style ASP.net application (with System.Web)

I have an old asp.net that I'd like to move from a Windows environment to Linux.
The application has an old Web.config, a bunch of dlls and an App_code folder.
Can you point me in the right direction to getting this working?
What I've tried so far:
dotnet publish -c Release -o /var/www/blah
But this complains:
app_code/Rewriter.cs(3,14): error CS0234: The type or namespace name 'Web' does not exist in the namespace 'System' (are you missing an assembly reference?
I read that System.Web doesn't really exist anymore.
My question is, can I reference some kind of build environment that will build and deploy this old-style application? Or so I need to port all the code?
Migrate any business logic to classes, so you can reuse it. The more code you can move to classes (or even class libraries), the easier it will be. Then create a new ASP.NET core application and rebuild the UI bits.
The hardest part is if you have a lot of spaghetti because you over-utilized the event methods in your code behind files. You may end up with a lot of refactoring, but the idea is to keep it working as is, but with the actual code outside of the ASPX pages. Once your event handlers look more like this
public void THisButton_Click(e as EventArgs)
{
OtherClass.Method();
}
you will find it much easier to migrate to MVC, which is how you will want to design the UI with for ASP.NET Core.
If this is not making sense, let me know, and I can see if I can point you to some information that helps.

How a dll is handled between different calls to an asp.net page?

I am in the start of developing an ASP.NET application and want to decide how to cluster functions in different dlls.
Suppose that I have an ASP.NET page that has to dll references, namely A.dll and B.dll. However B.dll uses some methods of A.dll.
Having this scenario, if somebody call my page.aspx where it calls B.dll, another A.dll will be loaded to memory or B.dll will use the same A.dll loaded by my page.aspx ?
Referenced libraries (dll) will be loaded when IIS is starting, some might be loaded on demand i'm not quite sure of that part. But none of your dlls would be loaded twice. dll is a code library, your code base containing definition of your implementation. Don't think of it as an instance of some custom class definition you made. Your dll might contain static classes, extension methods, helpers not only instantiable class definitions

What's the difference between C# Code Fragments and Assembly TBBs?

I understand C# Code Fragments and .NET Assemblies offer the same functionality for modular template development. We manage the code fragments in the CME and assembly code in Visual Studio, but use both the same way in Template Builder.
In terms of code, I can create a C# Code Fragment Template Building Block (TBB), for example:
var timeStamp = DateTime.Now.ToString("d MMM yyyy");
package.PushItem("timeStamp from fragment", package.CreateHtmlItem(timeStamp));
I can also create a .NET assembly Template Building Block using the same code by implementing ITemplate as below.
using System;
using Tridion.ContentManager.Templating;
using Tridion.ContentManager.Templating.Assembly;
namespace CreateAndBreakTemplates
{
[TcmTemplateTitle("Add Date to Package")]
public class AddDateToPackage : ITemplate
{
public void Transform(Engine engine, Package package)
{
var timeStamp = DateTime.Now.ToString("d MMM yyyy");
package.PushItem("timeStamp from assembly",
package.CreateHtmlItem(timeStamp));
}
}
}
The docs explain that "SDL Tridion inserts the code fragment in its predefined method of a predefined class." It looks like this class implements ITemplate and adds some references below (am I missing anything?).
The assembly setup instructions mention at least these dlls.
Tridion.Common.dll
Tridion.ContentManager.dll
Tridion.ContentManager.Templating.dll
Tridion.ContentManager.Publishing.dll
Any other difference between fragment and assembly and how would you choose between the two?
A C# fragment is compiled into an assembly by Tridion when the template is first invoked and after it's been modified. To compile the fragment, Tridion wraps it in some "dungeon dressing" (bonus points for those who know where that term comes from) that:
Uses the Tridion.ContentManager, Tridion.ContentManager.CommunicationManagement, Tridion.ContentManager.ContentManagement and Tridion.ContentManager.Templating namespaces
Makes the Package and Engine available in fields called package and engine respectively
Creates a logger for the C# fragment that is available through a field called log
Adds references to some commonly used assemblies (but does not add a using for their namespaces yet)
Edit: given the other answers it seems many people are not aware of how to accomplish certain tasks in C# fragment TBBs, so I'll document them below:
Import additional namespaces
To import/use additional namespaces into your C# fragment, you need to use this syntax:
<%# Import Namespace="Tridion.ContentManager.ContentManagement.Fields" %>
Note that this will only import namespaces from assemblies that are already referenced by Tridion. There is no mechanism for you to add references to other assemblies explicitly; so if you need a third-party DLL, you will need to add it to the GAC.
Defining custom functions
You can define custom fields and functions in your C# fragment by using this syntax:
<%!
public static string GetDate()
{
return new DateTime().ToString("u").Replace(" ", "T");
}
%>
Defining member fields and (nested) classes
The syntax for defining custom functions also allows you to define nested classes and/or member fields:
<%!
public class MyLittleHelper
{
public MyLittleHelper(string param1)
{
}
}
%>
Frank has explained the difference between the two approaches, but that still leaves the question of how to choose between the two. My personal advise is to never use C# fragments for anything, with only one exception*. As you have found out, there is some dark magic going on in them that I personally do not like. Also, there is so much you cannot do in them that a .NET programmer is quite fond of, such as creating classes.
Putting my personal taste aside, I see only one reason why you would ever resort to C# fragments: if you do not have access to Visual Studio or another tool that builds DLLs. And that is not a very strong argument either: if you want a job done, you should get the proper tools!
*The exception being the C# fragments that Tridion automatically creates for each ITemplate in your assembly, of course.
The main differences between C# code Fragment and .net Assemblies in my point of view are categorized into below high level buckets.
Step-by-Step Debugging
With .net assemblies you could do step-by-step debugging from visual studio where as C# Code fragments it is not possible.
Re-Use or Base Classes
With .net assemblies you could extend ITemplate to create something like BaseTemplate and all your template could extend them so you have common design pattern, where as C# there is no concept of BaseTemplate other than Tridion ITemplate interface.
With .net assemblies you could add common utility classes (often TridionUtilities) and all your templates refer to the same TridionUtilities for common functionality. C# code fragment the utility functions need to be defined within the same TBB and cannot be reused with other TBBs unless you create a class and deploy to GAC.
Easier Upgrade Scans and Maintenance
With .net assemblies it is easier to do any upgrade scans like deprecated APIs/Methods simply referring to new dlls/.net framework. .net assemblies make it easy to identify potential impacts on planning either Tridion upgrades or .net framework upgrades. C# code fragments it is much harder to find the deprecated or any impacts of upgrade.
Developer Friendly
Obviously .net assemblies are developed using Visual Studio (developers love it!) vs. C# Code Fragments in a Text Editor (painful).
When I started back with Tridion 5.3, started with C# code fragments and quickly realized what a mistake I made for not going .net assemblies.
My vote is always .net assemblies and C# code fragments is not even in consideration unless I don't have a choice. lol..
I think the differences indeed are best explained by Frank's answer, as to how would you choose between the two. I normally say, since you are using Visual Studio anyways, always create a .NET Assembly TBB for your code. They offer you a lot more benefits like including 3rd party assemblies, allow for proper coding with classes and methods a lot easier and probably most important, allow for proper debugging (although this last one can be hard to setup depending on where you are, thinking of customer environments, firewalls etc.).
There are for me only two exceptions for using C# Fragments:
The references to classes implementing ITemplate in an assembly, allowing you to use these as separate TBBs
If there is a requirement to manage constants or other hardcoded constants directly from SDL Tridion
Number 2 is of course debatable, but you never can do without configuration properties, for a TBB most of these you can handle using a Parameters Schema, but sometimes it is just a lot easier, to directly write them in a C# Fragment and have that push them to the package for other TBBs to use.
In my training sessions, I usually referred to the following story of the only time I ever choose to use a C# Fragment TBB so far, indicating how much of an exception it is to use them:
I was working at a customer abroad, and my taxi for the airport was leaving in 10 minutes when one of the developers I was coaching asked me a question on how to get a list of items from a Folder in his TBB. I had already closed my Visual Studio and Outlook and was about to shutdown my laptop, but quickly browsed through some of my code samples to find what he needed. Knowing that starting up Visual Studio or Outlook would take a few minutes, I quickly pasted the code in a C# Fragment so he had it for easy reference.
I would never use C# fragments for the sole reason that it makes management of your code quite difficult and you need to manually deploy them. And if you do write your code from Visual Studio, then you should create a .NET Building Block assembly.

Compiling/Embedding ASCX templated UserControls for reuse in multiple web applications

I'm onto a real head scratcher here ... and it appears to be one of the more frustrating topics of ASP.NET.
I've got an assembly that implements a-lot of custom Linq stuff, which at it's core has zero web functionality. I have an additional assembly that extends this assembly with web specific behaviour.
The web specific behaviour comes with a couple of user controls marked up inside ASCX templated UserControls.
I'm having trouble putting a nice finish on this assembly so that it is simple to redeploy for use in other applications. Let me run through what I've tried so far:
Copied the ASCX files to the consuming web application using build events; far from ideal and quite a deployment nightmare.
Implemented a custom VirtualPathProvider and embedded the ASCX templates within the assembly as embedded resources. Unfortunately when using the Register directive in the consuming application it creates the designer declaration as a UserControl, where I would require a declaration of the actual control type; unforeseen (typically) and undesirable.
Created a Web Deployment Project to compile the UserControls, but the compiled user controls then become part of another assembly, and no longer descend from the class definitions in my web assembly--the assembly needs to instantiate them dependent on the request context.
So number 1 is just crap, number 2 doesn't give me the type support I desire and number 3 I think I'm about to produce a reasonable solution with:
Lump all non-control classes into the App_Code folder, prepare a factory class that will construct an object of the desired control type using reflection and the expectation that the type being reflected will be present in the deployment output (hopefully guaranteed by the presence of the ClassName attribute in the Control directive).
Theres also always the other option of rewriting the ASCX controls into custom controls, but just don't have the resources to consider it at the moment, and we've got no expertise in doing that, and they work fine as UserControls.
Am I missing something obvious, something maybe much simpler, or is this just purposefully difficult? I've read stories of the ASP.NET compilation process being very unfortunate in it's design on my travels across this topic.
Well I think I've done it ... by being mindful of a few of a few annoying pitfalls with my last approach, I recommend the following when compiling ASCX user controls in a Web Application Project using a Web Deployment Project:
Avoid putting classes in App_Code unless they're standalone or helper classes, ASP.NET treats this as a speshul folder, the meaning of which is lost on me, mayhem, confusion and chaos follows. Code in this folder does get output in the Web Deployment Project, though.
Pay close attention to your assembly names, their root namespaces and deployment output assembly name- you'll get access is denied errors if you have any naming conflicts during the aspnet_merge process.
Ultimately you'll most likely end up deploying 2 assemblies, I tried to create only one but the deployment output was still pointing to type definitions in the source assembly. This isn't a problem if you don't have any other types in your Web Application Project--I have so it was a problem for me. In my case, my final output was:
<Organisation>.<TechnologyName>.Web.DLL - Compiled Web Application Assembly (containing the ASCX templates)
<Organisation>.<TechnologyName>.Web.UI.DLL - ASP.NET Compiled UserControl assembly, created by Web Deployment Project
Clean often, and check that the Web Application Project's bin and obj paths are cleared of any previous junk built when you perhaps hadn't finalised your namespace or assembly naming scheme--the Web Deployment Project will be quite keen to include these, causing a fine mess.
Check your imported namespaces, the ASP.NET compiler likes to refer to the Import directive in the ASCX template, and it also considers imported namespaces present in web.config's <configuration><system.web><pages><namespaces> element, tweak if you get unknown definitions appearing during the deployment process.
Have some patience spare, it's quite tricky! But you do get some nice re distributable UserControls at the end of it!
Phew!

Problem reflecting in ASP.net context

I have a ASP.net application that is referencing a external assembly that I need to dynamically load and discover any types implementing a known interface. The problem I am having is that the type I reflect does not match the same interface that is running and so I cannot cast it.
Example:
This code is run in ASP.net app.
var assembly = Assembly.LoadFile(Path.Combine(HttpRuntime.BinDirectory, "ExternalAssembly.dll"));
var type = assembly.GetExportedTypes().First<Type>(x => x.Name == "AClass"); // AClass implements IAInterface
var reflectedInterface = type.GetInterface(typeof(IAmAInterface).ToString());
if (reflectedInterface != typeof(IAmAInterface))
throw new Exception("This makes me sad"); // This code gets run
The only difference I can see between the reflected interface I loaded from the bin and the interface returned from typeof is that the typeof assembly has a location in the temp ASP.net path (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\root\08c43c8b\3adac8cf\assembly\dl3\eb7a4127\0235ea60_a3c8c901\ReflectionTest.DLL)
Thanks Paul Alexander I have changed the code to use the Assembly.Load method not Assembly.LoadFile which solves the problem.
wwilden: I also tried extracting the interface into it's own assembly and this does also solve the problem.
When you use LoadFile the assembly is not loaded into the same context as your other assemblies at runtime so to the CLR interface runtime types are different. You can read more in Suzanne Cook's Debugging Assembly Load Failures.
If the assembly that you're loading is already in the Bin directory - you can load it by name. You don't need to know the exact path as the Bin folder is already in the assembly probing path.
Where is your interface type defined? Does it exist both in the reflected assembly as well as in the application itself? Then you actually have two different interfaces, even though they have the same namespace and name.
What you need to do is extract the interface from the reflected assembly and put it into another assembly that you refer to both from the reflected assembly as well as your application. Then it should work.
Apart from your problem, if you have a lot of assemblies to dynamically load, remember that they will remain in memory until the ASP.NET worker process reloads. This could influence your server's performance.
You could load the assemblies in a separate AppDomain (the smallest unit that is possible to unload), load a proxy class in that AppDomain which you reference with .NET remoting. Once finished, you unload the AppDomain.
There is an interesting article over at CodeProject about a situation like this. Where you have a class that has a structure that is identical with an interface without implementing the interface itself. The article outlines a method of dynamically creating wrapper classes that implement the needed interface. It could be helpful in your situation.

Resources