ASP.NET - context-agile object,Data sharing concept in application domain? - asp.net

I read some articles about Application Domain.The deep reading finally resulted in whirling
confusion.So I submit the questions to subject experts.
1) As CLR takes care of creating AppDomain as and when needed,could there be a critical
need to go for manual Application Domain Creation ?
2)I heard that one application domain can not share data with other application domain (i
am not sure).What about the case of windows communication foundation ?
3) Normally the basic libraries (system.dll,mscorlib.dll) are loaded in default application domain. can i load them in custom created application domain ? if it is possible,will CLR keep a copy in Default application domain ?
like
------------------ ----------------
Default AppDomain Custom Appdomain
------------------- ----------------
mscorlib.dll mscorlib.dll
System.dll System.dll
..... .......
----------------- -----------------
4) What is the term context-agile object in application domain referes to?

Creating your own AppDomains is useful sometimes when you want isolation (e.g. sandboxing 3rd party code), or the ability to reload code which changes during execution. (You can't unload an assembly, but you can unload an AppDomain.)
Sharing data between AppDomains involves marshalling. The data can either be marshalled by value (i.e. everything gets copied) or by reference if your object derives from MarshalByRefObject. In the latter case, what actually gets through to the other AppDomain is a reference to a proxy object. Anything you do on the proxy is actually done to the real object in the original AppDomain.
Not entirely sure what you mean. You can certainly use all the system assemblies in other AppDomains.
I haven't come across this term, that I can remember.

AppDomains can pass information from one to the other using services, such as WCF as you said in question 2.

Related

BuildManager.GetReferencedAssemblies equivalent for non-web applications

Compared to AppDomain.GetAssemblies(), BuildManager.GetReferencedAssemblies() (System.Web.Compilation.BuildManager) seems a more reliable way to get the assemblies that are referenced by an ASP.NET application at runtime, since AppDomain.GetAssemblies() only gets "the assemblies that have already been loaded into the execution context of this application domain".
Iterating through all assemblies is an important tool for dynamically registering types at application start-up in your DI container and especially during application start-up, chances are that other assemblies are not loaded (where not needed) yet, and the composition root is the first one that needs them. It is therefore very important to have a reliable method to get the application's referenced assemblies.
Although BuildManager.GetReferencedAssemblies() is a reliable method for ASP.NET applications, I'm wondering: what alternatives are available for other types of applications, such as desktop applications, windows services and self-hosted WCF services?
The only way I currently see is pre-fetching all referenced assemblies manually, just as the BuildManager does under the covers:
var assemblies =
from file in Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory)
where Path.GetExtension(file) == ".dll"
select Assembly.LoadFrom(file);
I've had the same problem. And after doing some research I've still not found a solid answer. The best I've come up with is to combine AppDomain.CurrentDomain.GetAssemblies() with the AppDomain.AssemblyLoad event.
In that way I can process all already loaded assemblies while getting notified for all new assemblies (which I then scan).
This solution is based on #steven's answer.
But would work in Web, WinForms, Consoles, and Windows Services.
var binDirectory = String.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath) ? AppDomain.CurrentDomain.BaseDirectory : AppDomain.CurrentDomain.RelativeSearchPath;
var assemblies = from file in Directory.GetFiles(binDirectory)
where Path.GetExtension(file) == ".dll"
select Assembly.LoadFrom(file);

Where and how does the assembly references are serialized or deserialized in Biztalk

I've got stuck with a problem. I've an BizTalk 2010 application which references a Third party Schema dll. Our Architect told us not to directly reference it as it'll take more time to serialize this huge around 9MB dll which will cause Biztalk work more.
Since this Third part dll is a schema dll it'll be deployed to MgmtDb under any of the applications prior any other app deployment. Our orchestration messages has messagetypes which are referenced from this schema dll.
What I want to know is where excatly this serialization of this external dll taking place as the this dll already been deployed and Orchestration instance can reference this against any request messages which comes in.
Do serialization happen for each message which creates an orchestration instance.
Please share your thoughts.
Thanks.
While its true that the referenced assembly will be added into MgmtDB, AFAIK it is only metadata about the assembly and the artifacts in it which is added, e.g.
use BizTalkMgmtDb
select * from dbo.bts_assembly
... dbo.bts_orchestration
... dbo.bt_DocumentSpec
etc.
Possibly he/she is refering to instances of messages created from schema classes in the assembly (and are stored in the messagebox). But the size of the messages will be determined by the size of the data in it, not by the size of the assembly.
Since you seem to need the referenced message schemas, there isn't much option but to reference it in your new project (e.g. unless you have the source to the 3rd party assembly where you could refactor it and split it into several smaller assemblies). The 3rd party assembly needs to be deployed on your BizTalk servers and signed and GACed.
However if this referenced schema assembly also contains other artifacts like custom classes used in orchestrations as variables, these classes will also need to be serializable as soon as the orchestration hits a dehydration point (to avoid this you would need to scope the variables out before the dehydration and / or use an atomic scope to prevent BizTalk from dehydrating at all, but this is generally a bad idea as it will limit scalability)
Your Architect has made an incorrect assumption about when BizTalk performs validation of a Document against its defined Schema.
Validating a large Document against a hefty Schema, such as an EDIFACT or OASIS, can take a lot of resources. BizTalk therefore will not validate an incoming Document against its relevant schema unless you explicitly ask it to do so in the Receive Pipeline. By default, most Pipeline components will have their 'ValidateDocument' property set to 'False'. BizTalk will therefore only perform Document recognition, based on the namespace and root node, and this is done while stream-reading the first couple of hundred bytes of the document stream.
So, you can freely 'reference' the third party DLL, the only performance penalty will be at compile and deployment time. If, for some reason, you need to validate a Document against this Schema, you would need to have it in the Management DB regardless.

Why do ASP.NET resolve assembly references differently?

I really tried hard to find a similar issue to get some leads, but no one seems to describe the case we are having, so here it goes.
Background
We have a product with the following general design:
[Local installation folder]
Contains a set of .NET assemblies, implementing the bulk of our product functionality.
Example: Implementation1.dll, Implementation2.dll
[GAC]
ClientAPI.dll. Our client assembly, to be referenced from end user Visual Studio projects. Has strong references to the implementation dll's in the local installation folder.
In ClientAPI.dll, we have an entrypoint we require end user projects to invoke. Lets call it Initialize().
The very first thing we do in Initialize is to install a so called assembly resolve handler on the current domain, using the AssemblyResolve event. This handler will know how to locate the implementation dll's and load them into the client process, using Assembly.Load().
Consider a console application. It will look something like:
class Class1
{
void Main(string[] args)
{
ClientAPI.Initialize();
// Use other API's in the assembly, possibly internally referencing the
// implementation classes, that now will be resolved by our assembly
// resolve handler.
}
}
Now, all is good in the console/windows forms/WPF world. Our assembly resolve handler is properly installed and invoked, and it can successfully resolve references to the implementation DLL's once ClientAPI.dll require their functionality.
Problem statement
With that being said, we intend not to support only console or WPF applications, so we were relying on the same design in ASP.NET. Hence, creating a new ASP.NET Web Application project in VS 2010, we figured everything would be as straightforward as:
class Globals : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
ClientAPI.Initialize();
// ...
}
}
A few 20-30 hours of dwelling in the ASP.NET runtime universe, trying the above in both the development server and in IIS, we've learned that things there are not really as we expected.
It turns out that in ASP.NET, as soon as the ClientAPI class is referenced anywhere, all references it has to any other assemblies are instantly resolved. And not only that: the results are cached (by design, since .NET 2.0 we've found), meaning we never have a chance at all trying to assist the CLR.
Without further elaboration about the different things we've tried and learned, it basically comes down to this question we have:
Why is ASP.NET resolving references like this? It is not compatible with how other types of applications does it, and even more, it is not according to the documentation of .NET / the CLR runtime, specifying that references to external types / assemblies are to be resolve when first needed (i.e when first used in code).
Any kind of insight/ideas would be highly appreciated!
Windows Forms / WPF applications run on individual client machines (and therefore run in a single, local context), whereas ASP.Net runs within IIS, within an application pool, on a server or set of servers (in a web farm situation). Whatever is loaded in to the application pool is available to the entire application (and therefore is shared between all clients who connect to the application).
HttpApplication.Application_Start is executed once, when the application starts up. It is not executed per client as it would be with a Winforms application - if you need to initialize something for every client that connects, use Session_Start or Session_OnStart, but then you may run in to memory issues with the server, depending on how many clients are going to connect to your web application. This also depends on whether your class is a singleton, and if the Initialize() method is static. If you have either of those situations, you're going to run in to cross-threading problems fairly quickly.
Additionally, it's worth noting that an idle IIS application pool will reset itself after a period of time. If no one uses the web application overnight, for example, IIS will flush the application's application pool and free up memory. These settings can be changed within IIS administration, but you should be careful when doing so - changing these settings to circumvent a badly designed object (or an object that isn't designed for a web application) can create even more problems.
FYI - I'm being a little fussy, but for the avoidance of doubt, the object is not cached - yes, it is loaded in to memory, but how the memory is managed is up to how you've designed the object (caching in the web world is an entirely different thing, and can be implemented in many different layers of your application).
Don't try and make a web application act like a windows application; you'll just create yourself more problems!

cannot be cast to [B]; Same context (Default); Different Temp File

I'm having difficulty finding why exactly the following error is happening. I'll outline the puzzling aspects below the error description.
[A]ASP.common_resultmessagepanel_ascx cannot be cast to[B]ASP.common_resultmessagepanel_ascx.
Type A originates from 'App_Web_resultmessagepanel.ascx.38131f0b.2c4hpv_z, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location
'C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\MyWebApp\dc3e0df6\ba1606c8\App_Web_resultmessagepanel.ascx.38131f0b.2c4hpv_z.dll'.
Type B originates from 'App_Web_wz3shqfq, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location
'C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\MyWebApp\dc3e0df6\ba1606c8\App_Web_wz3shqfq.dll'.
The class referenced in the error is a web user control inheriting from System.Web.UI.UserControl and implementing System.Web.UI.ITextControl. The control is registered and used on a master page. None of the parent master pages or implementing pages have instances of the control. The class and the markup page are both in the web application project. The exception does not happen as a direct result of the application code, it happens during internal .NET Framework code execution. The project is a web application, not a web site. The web application is compiled into a single binary, with culture specific resources compiled into one binary per culture.
The context reported for each type in the exception is the same, but I was able to verify that when the exception occurs there are in fact 2 separate class definitions in the Temporary ASP.NET Files folder for the application.
The user control has always existed and was used in the application, but the exception first started happening after the user control was added to a master page.
The exception does not happen consistently. Once the temporary files get created, the exception will happen every time the page is requested. If anything causes the temporary files to be cleared or recreated, it is random as to whether the duplicate temporary class definitions/DLLs will be created again. This could be a web.config change, recycling the app pool, sometimes even just an updated/rebuilt web application binary.
The last bit of the stack trace:
ASP.Default.__BuildControl__control35(Control ctrl) in C:\Projects\ABC.Web\App_Themes\Default\CheckBox.skin:3
System.Web.UI.ControlSkin.ApplySkin(Control control) +12
System.Web.UI.PageTheme.ApplyControlSkin(Control control) +119
System.Web.UI.Control.ApplyStyleSheetSkin(Page page) +61
ASP.masterpages_mymaster_master.__BuildControlpnlResults() in C:\Projects\ABC.Web\MasterPages\MyMaster.master:10
ASP.masterpages_mymaster_master.__BuildControl__control2(Control __ctrl) in C:\Projects\ABC.Web\MasterPages\MyMaster.master:9
System.Web.UI.CompiledTemplateBuilder.InstantiateIn(Control container) +12
System.Web.UI.MasterPage.InstantiateInContentPlaceHolder(Control contentPlaceHolder, ITemplate template) +87
The supposed offending source (the only line in the skin file C:\Projects\ABC.Web\App_Themes\Default\CheckBox.skin):
<asp:CheckBox runat="server" SkinID="FormInput" CssClass="FormLabel FormInputCheckBox" />
At this point I don't know if this issue is caused by the solution, its configuration, IIS and the app pool, or something related to the actual temp file directory itself where maybe old files are not getting cleared out. I've verified that the temp folder is not being indexed by the OS.
I'm worried that in a production environment, the app pool will recycle or some configuration setting will change and cause those temp files to be recreated with the duplicate class definition, and thus the error. We can't have someone testing the application every time the app pool recycles and deleting temp files if the error occurs until the application loads correctly. So I need to find out what is causing the duplication, but at this point I don't really know where else to investigate.
Any ideas?
I've removed the user control from the master page, and put it directly into each of the pages that required it and were implementing the master page.
So far the exception hasn't happened again. I'm going to give it another couple days of test time to see if it crops up again.
I still want to know why the exception was happening at all. Anyone with in-depth knowledge of how IIS runs .net web apps, or how the temp files are created?
New theory!
While it is a web project with a compiled binary, the IIS instance I am running for development is pointed to the project folder. So the source code files are actually in the web path. I think IIS might be compiling the source code files into separate binaries, especially if the app pool recycles. Thus accounting for the duplicated temp files that are being created and the error.
Other developers were experiencing the errors while running the project from within visual studio. I don't know how this would account for those cases, but I wouldn't rule it out as being the cause either.
I'm not sure what's happening in your case, but I had this happen to me under the following circumstances:
Website project type, not Web Application.
/Controls folder containing many ascx usercontrols.
/Client/Controls folder containing other ascx usercontrols, some of which register and reference /Controls usercontrols.
/Controls/BadControl.ascx using /Client/Controls/DupedControl.ascx as a child control.
The compiler runs into a circular dependency as it tries to compile each folder into a separate assembly.
/Controls/BadControl.ascx needs /Client/Controls to be compiled first.
/Client/Controls needs /Controls to be compiled first.
So the compiler punts and compiles DupedControl.ascx into its own separate assembly first. Then /Controls, then /Client/Controls in which DupedControl still gets included.
At this point there are two distinct Types for DupedControl in two separate assemblies. DupedControl.ascx (markup) points to the correct Type -- let's call it TypeA, in the folder's assembly -- while BadControl's reference points to the dupe TypeB in the small extra assembly.
When a page using BadControl executes, DupedControl TypeA gets instantiated via the markup, but BadControl tries to cram it into a TypeB variable, resulting in the error you described.
The solution is to move ascx files around to get rid of the circular reference. I can't remember for certain, but I think maybe the "single page assemblies" and "fixed naming" options might also resolve it.
All that said, Web Application projects compile to a single assembly, so I didn't think this kind of circular folder reference would be possible. Perhaps the problem lies elsewhere.
After a year and a half of seeing this error intermittently pop up for developers in our team, I've finally been able to gather enough data to draw some conclusions.
The key elements in the scenario causing the error are source code files in the web path, and low available memory on the dev machine that is running the application. The low memory condition causes the application pool to recycle or release memory more frequently than it would in a dedicated web hosting environment. When the memory containing the compiled web app code is released, and then a page is requested, the compiled code is reloaded into app pool memory. Since source code files are in the web path, .NET recompiles from the source code files and reloads into memory.
This situation does not happen in a dedicated hosting environment where only the compiled DLL and static files are deployed, and has never happened in our production environment. Additionally memory usage in a dedicated environment should ideally never reach a point where frequent app pool recycling is necessary.
The Visual Studio solution consists of several projects, and developers typically have multiple VS instances, a SQL Server Mgmt instance, and other sundry processes running which cause low available memory on dev machines. The lower the available memory, the more frequently and reliably the error will happen.
To clear the error state, an application pool flush / iisreset will clear out memory, and then a rebuild will usually fix the problem. If available memory is still low, the problem may persist until more memory is available in which to run the application. Simply closing down some applications or otherwise releasing memory back to the OS should do the trick.
I'm still not sure why running the app through Visual Studio's web server instead of IIS has same issue, but if it handles memory the same way IIS does, it stands to reason that the behavior is the same.
SOLVED!
I had similar problem, caused from LoadControl() strange behaviour.. and solved not instantiating my control before.
strange but true..
MyUserControl myuc = new MyUserControl();
myuo = (MyUserControl)Page.LoadControl("~/UserControls/MyUserCOntrol.ascx");
doesnt work
MyUserControl myuc = (MyUserControl)Page.LoadControl("~/UserControls/MyUserCOntrol.ascx");
works
I belive we found a solution to this problem. We always tried fixing this by deleting the whole "Temporary ASP.NET Files" folder.
At some point this solution would no longer be good enough and the error kept popping up every 30 minutes or so. We found that deleting just the file responsible and then restarting the application pool of the application in question is a permenant fix (at least for us). So for you case you would delete the follwing file (bold) and then restart the applications application pool:
[A]ASP.common_resultmessagepanel_ascx cannot be cast to
[B]ASP.common_resultmessagepanel_ascx.
Type A originates from 'App_Web_resultmessagepanel.ascx.38131f0b.2c4hpv_z, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location
'C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\MyWebApp\dc3e0df6\ba1606c8\App_Web_resultmessagepanel.ascx.38131f0b.2c4hpv_z.dll'.
Type B originates from 'App_Web_wz3shqfq, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
in the context 'Default' at location
'C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\MyWebApp\dc3e0df6\ba1606c8\App_Web_wz3shqfq.dll'.
This permenantly fixed the problem for us.
EDIT:
Found a permenant solution, at least for us.
In web.config look for tag and add batch="false" to it. So it would look something like:
compilation debug="false" targetFramework="4.7.2" batch="false"
The error never repeated after this.

Where should connection strings be stored in a n-tier asp.net application

Folks,
I have an ASP.NET project which is pretty n-tier, by namespace, but I need to separate into three projects: Data Layer, Middle Tier and Front End.
I am doing this because...
A) It seems the right thing to do, and
B) I am having all sorts of problems running unit tests for ASP.NET hosted assemblies.
Anyway, my question is, where do you keep your config info?
Right now, for example, my middle tier classes (which uses Linq to SQL) automatically pull their connection string information from the web.config when instantiating a new data context.
If my data layer is in another project can/should it be using the web.config for configuration info?
If so, how will a unit test, (typically in a separate assembly) provide soch configuration info?
Thank you for your time!
We keep them in a global "Settings" file which happens to be XML. This file contains all the GLOBAL settings, one of which is a connection string pointing to the appropriate server as well as username and password. Then, when my applications consume it, they put the specific catalog (database) they need in the connection string.
We have a version of the file for each operating environment (prod, dev, staging, etc). Then, with two settings -- file path (with a token representing the environment) and the environment -- I can pick up the correct settings files.
This also has the nice benefit of a 30 second failover. Simple change the server name in the settings file and restart the applications (web) and you have failed over (of course you have to restore your data if necessary).
Then when the application starts, we write the correct connection string to the web.config file (if it is different). With this, we can change a website from DEV to PROD by changing one appSettings value.
As long as there isn't too much, it's convenient to have it in the web.config. Of course, your DAL should have absolutely no clue that it comes from there.
A good option is for your data layer to be given its config information when it is called upon to do something, and it will be called upon to do something when a web call comes in. Go ahead and put the information in your web.config. In my current project, I have a static dictionary of connection strings in my data layer, which I fill out like so in a routine called from my global.asax:
CAPPData.ConnectionStrings(DatabaseName.Foo) =
ConfigurationManager.ConnectionStrings("FooConnStr").ConnectionString()
CAPPData.ConnectionStrings(DatabaseName.Bar) =
ConfigurationManager.ConnectionStrings("BarConnStr").ConnectionString()
etc.
"Injecting" it like this can be good for automated testing purposes, depending on how/if you test your DAL. For me, it's just because I didn't want to make a separate configuration file.
For testing purposes don't instantiate DataContext with default ctor. Pass connection string info to constructor.
I prefer to use IoC frameworks to inject connection to data context then inject context to other classes.

Resources