Something is seriously wrong with my ASP.NET MVC - asp.net

I have been programming ASP.NET Web Forms for a long time and recently decided to learn ASP.NET MVC.
However, I am clearly having some issues that I cannot tell how. No one that I have come across in web had the same problems.
#1: Web.config issues
When I first created my MVC project in VS2019, there was no web.config so I added it via project > add new item> Web Configuration File.
All I needed it for was to store my connection string. When added it had only two lines of code:
<configuration>
</configuration>
I added my connection string and the file looked like this:
<configuration>
<connectionStrings>
<add name="connection" connectionString="myconnectionstringblablabla" />
</connectionStrings>
</configuration>
In my controller I tried to fetch the connection string by doing,
string constr = ConfigurationManager.ConnectionStrings["connection"].ConnectionString;
And this happened:
Same things happens when fethcing AppSetting keys from web.config.
Is web.config not meant to be used for ASP.NET MVC?
#2 Global.asax
Unlike web.config, Global.asax file doesn't even show up on the add new item menu:
Tried this solution: How to add a Global.asax file to ASP.NET MVC5 project Didnt work either.
#3 Session & HttpContext
In ASP.NET Web.Forms, I would normally use Session variables like this:
Session["ClientID"] = somevalue;
I can't do that in ASP.NET MVC, although I have seen people doing it.
Also I can't access to HttpContext from a non-controller class:
HttpContext.Current.Request.Cookies["mycookie"];
It throws HttpContext does not contain a definition for 'Current'...
====================================
Is Something wrong with my program. I don't know how to check if I am using correct references or assemblies, but I think I am missing something.
Please help

Related

Routing an ASP page to a Action in ASP.NET MVC

I am recreating a site from VB .NET to MVC 4 ASP.NET. In the old project there is a system that sends an email to a user and within that email there is a hyperlink that can direct the user to view the specific task. I want to make all of the old emails work with the new recreated site. Here is an example of the hyperlink in the old system:
http://pppweb/accounting/ap/default.asp?etaskid=32698
And here is an example of what a hyperlink looks on the new system.
http://pppweb/accounting/ap/ApIssues/Task/32698
So I was thinking i could create a default.asp page in my MVC project and try and have it parse the taskID out. I am not exactly sure the best way to go about doing this?
I would advise against adding a classic .asp (not .aspx?) page in your project, since I'm not even sure there is a way to do that. You can, assuming you are running IIS7, map the url:
http://pppweb/accounting/ap/default.asp
to be handled by MVC by adding the following line to your web.config file:
<configuration>
...
<system.webServer>
...
<handlers>
...
<add name="aspnet htm" path="account/api/default.asp" verb="*" type="System.Web.Mvc.MvcHttpHandler" preCondition="integratedMode" />
Then, add a route for that url and requests should resolve to the normal route parameters you specify. From that point, you should be able to access etaskid from the query string easily enough.
Edit:
Alternatively, if the url matters a lot to you, you can specify a redirect rule from the old format url to the new one by using UrlRewrite module (also an IIS 7 feature). You can read about it here: http://www.iis.net/downloads/microsoft/url-rewrite

Custom VirtualPathProvider not being used in IIS6

I added the following lines to Application_Start method in global.asax:
var provider = new TestVirtualPathProvider();
HostingEnvironment.RegisterVirtualPathProvider(provider);
Yet the 'TestVirtualPathProvider' is never used when deploying this application in IIS6 (it does in the ASP.NET Development Server).
Edit: the default path provider has always done its job correctly and served (non-embedded) views correctly. The problem is simply that I want to use my own path provider to provide embedded views. So, initially, I already had the following wildcard mapping configured:
Any possible reasons why this does not work in IIS6?
Are there any other factors (handlers for example) wich might influence the used VirtualPathProvider?
UPDATE: the fact that you want to handle extension-less URL's is an important point that's not mentioned in the question. Please see this page for help in setting up MVC with IIS 6: http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx. This should cover your scenario as well.
Most likely the same issue that I answered in this thread: http://forums.asp.net/t/995633.aspx
Basically, add this in your web.config:
<httpHandlers>
<add path="*" verb="GET,HEAD,POST" type="System.Web.StaticFileHandler" validate="true" />
</httpHandlers>
That other thread has some details that explain why this is necessary.
For the combination Custom VPP + IIS6 + Precompiled site, we need to add the VPP from AppInitailize();
public static class AppStart
{
public static void AppInitialize()
{
// code to be executed automatically by the framework
}
}
See also:
http://sunali.com/2008/01/09/virtualpathprovider-in-precompiled-web-sites/
I believe that you need to use an ISAPI filter in IIS6 to intercept URLs without extensions. Problem is that ISAPI will need to be done in c/c++.
IIS6 is configured to allow only certain extensions to be processed by the ASP.net pipeline.
To findout how you can redirct requests check out the post by DocV.

ASP.NET get windows username outside of page

I have an Existing ASP.NET reporting application using windows authentication. A lot of the report generation code is in separate classes and has a core error logger that I didn't write, this error logger I believe was built for windows apps as it uses WindowsIdentity.GetCurrent().Name. In the case of ASP.NET I believe this will return the account running the ASP.NET pages at the server.
I believe using User.Identity.Name on the pages would be the correct way to do this but it is not available from within the report generation classes only on the page. Is there a way to obtain it withing the error logger class without passing it as an extra parameter.
There are hundreds of report classes so I dread to have to go through and add a parameter to every one.
If you can use impersonation in your web.config:
....
<authentication mode="Windows"/>
<identity impersonate="true"/>
....
your report classes will get the right user.
If your reporting classes can reference the System.Web assembly and you are willing modify the code, you could also do:
HttpContext.Current.User.Identity.Name
but make sure the caller comes from an ASP.NET request or it will throw a nullref.

Creating a web service without an ASMX file?

I have written an ASP.NET composite control which includes some Javascript which communicates with a web service.
I have packaged the classes for the control and the service into a DLL to make it nice and easy for people to use it in other projects.
The problem I'm having is that as well as referencing the DLL in their project, the consumer of my control must also include a .ASMX file for the web service. Whilst it isn't a complicated file (just a one-liner which refers to the class in the DLL), I would like to avoid having it if I can.
Is there any way to avoid having to have the .ASMX file?
Can I register the service with the web server in Application_Start?
Can I make a web.config change to reference it somehow?
All suggestions gratefully received!
UPDATE: The article linked to in John Sheehan's response (below) does work - but not if you want to call the web service using AJAX. Does anybody know of an AJAX friendly version?
Try something like this. I don't know if it will work though. I got this idea from ELMAH, which creates a handler for a page that doesn't physically exist and then serves it up from the assembly.
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="*WebService.asmx" type="MyHandler.WebServiceHandler, MyHandler" />
</httpHandlers>
</system.web>
</configuration>
EDIT: I was close, see this article (in VB though): http://www.codeproject.com/KB/aspnet/wsinaclasslibrary.aspx
I know this is very old question, but it hasn't been answered properly, so here it is:
Every *.ASMX request is by default handled by System.Web.Services.Protocols.WebServiceHandlerFactory.
Looking into source code of this class in .NET reflector, it's possible to have webservice without ASMX file but you will need to call internal method CoreGetHandler through reflection.
Following method will take your webservice and return its IHttpHandler.
public IHttpHandler GetHttpHandlerForWebService(WebService webService, HttpContext context)
{
var webServiceType = webService.GetType();
var wshf = new System.Web.Services.Protocols.WebServiceHandlerFactory();
var coreGetHandler = wshf.GetType().GetMethod("CoreGetHandler");
var httpHandler = (IHttpHandler)coreGetHandler.Invoke(wshf, new object[] { webServiceType, context, context.Request, context.Response });
return httpHandler;
}
Once you have your httphandler, it's just matter of calling
httpHandler.ProcessRequest(context)
Done. No ASMX and no web.config entries.
Here is a very good working article about your problem:
Creating Web Services in a Class Library project on Codeproject.
Consider trying page methods (see this blog post). All you have to do is add the web method attribute to a static method in the aspx code behind. Then access the PageMethod object from your clientside code (javascript). No ASMX files needed. Hope this helps.
Short answer is no. The ASMX is the entry point for any web service. There are alternatives if you use WCF, but that's not entirely the same thing.

How do you modify the web.config appSettings at runtime?

I am confused on how to modify the web.config appSettings values at runtime. For example, I have this appSettings section:
<appSettings>
<add key="productspagedesc" value="TODO: Edit this default message" />
<add key="servicespagedesc" value="TODO: Edit this default message" />
<add key="contactspagedesc" value="TODO: Edit this default message" />
<add key="aboutpagedesc" value="TODO: Edit this default message" />
<add key="homepagedesc" value="TODO: Edit this default message" />
</appSettings>
Let's say, I want to modify the "homepagedesc" key at runtime. I tried ConfigurationManager and WebConfigurationManager static classes, but the settings are "read-only". How do I modify appSettings values at runtime?
UPDATE:
Ok, so here I am 5 years later. I would like to point out that experience has told me, we should not put any configuration that intentionally is editable at runtime in the web.config file but instead we should put it in a separate XML file as what one of the users commented below. This will not require any of edit of web.config file to restart the App which will result with angry users calling you.
You need to use WebConfigurationManager.OpenWebConfiguration():
For Example:
Dim myConfiguration As Configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~")
myConfiguration.ConnectionStrings.ConnectionStrings("myDatabaseName").ConnectionString = txtConnectionString.Text
myConfiguration.AppSettings.Settings.Item("myKey").Value = txtmyKey.Text
myConfiguration.Save()
I think you might also need to set AllowLocation in machine.config. This is a boolean value that indicates whether individual pages can be configured using the element. If the "allowLocation" is false, it cannot be configured in individual elements.
Finally, it makes a difference if you run your application in IIS and run your test sample from Visual Studio. The ASP.NET process identity is the IIS account, ASPNET or NETWORK SERVICES (depending on IIS version).
Might need to grant ASPNET or NETWORK SERVICES Modify access on the folder where web.config resides.
Changing the web.config generally causes an application restart.
If you really need your application to edit its own settings, then you should consider a different approach such as databasing the settings or creating an xml file with the editable settings.
And if you want to avoid the restart of the application, you can move out the appSettings section:
<appSettings configSource="Config\appSettings.config"/>
to a separate file. And in combination with ConfigurationSaveMode.Minimal
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
config.Save(ConfigurationSaveMode.Minimal);
you can continue to use the appSettings section as the store for various settings without causing application restarts and without the need to use a file with a different format than the normal appSettings section.
2012
This is a better solution for this scenario (tested With Visual Studio 2008):
Configuration config = WebConfigurationManager.OpenWebConfiguration(HttpContext.Current.Request.ApplicationPath);
config.AppSettings.Settings.Remove("MyVariable");
config.AppSettings.Settings.Add("MyVariable", "MyValue");
config.Save();
Update 2018 =>
Tested in vs 2015 - Asp.net MVC5
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
config.AppSettings.Settings["MyVariable"].Value = "MyValue";
config.Save();
if u need to checking element exist, use this code:
var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
if (config.AppSettings.Settings["MyVariable"] != null)
{
config.AppSettings.Settings["MyVariable"].Value = "MyValue";
}
else { config.AppSettings.Settings.Add("MyVariable", "MyValue"); }
config.Save();
I know this question is old, but I wanted to post an answer based on the current state of affairs in the ASP.NET\IIS world combined with my real world experience.
I recently spearheaded a project at my company where I wanted to consolidate and manage all of the appSettings & connectionStrings settings in our web.config files in one central place. I wanted to pursue an approach where our config settings were stored in ZooKeeper due to that projects maturity & stability. Not to mention that fact that ZooKeeper is by design a configuration & cluster managing application.
The project goals were very simple;
get ASP.NET to communicate with ZooKeeper
in Global.asax, Application_Start - pull web.config settings from ZooKeeper.
Upon getting passed the technical piece of getting ASP.NET to talk to ZooKeeper, I quickly found and hit a wall with the following code;
ConfigurationManager.AppSettings.Add(key_name, data_value)
That statement made the most logical sense since I wanted to ADD new settings to the appSettings collection. However, as the original poster (and many others) mentioned, this code call returns an Error stating that the collection is Read-Only.
After doing a bit of research and seeing all the different crazy ways people worked around this problem, I was very discouraged. Instead of giving up or settling for what appeared to be a less than ideal scenario, I decided to dig in and see if I was missing something.
With a little trial and error, I found the following code would do exactly what I wanted;
ConfigurationManager.AppSettings.Set(key_name, data_value)
Using this line of code, I am now able to load all 85 appSettings keys from ZooKeeper in my Application_Start.
In regards to general statements about changes to web.config triggering IIS recycles, I edited the following appPool settings to monitor the situation behind the scenes;
appPool-->Advanced Settings-->Recycling-->Disable Recycling for Configuration Changes = False
appPool-->Advanced Settings-->Recycling-->Generate Recycle Event Log Entry-->[For Each Setting] = True
With that combination of settings, if this process were to cause an appPool recycle, an Event Log entry should have be recorded, which it was not.
This leads me to conclude that it is possible, and indeed safe, to load an applications settings from a centralized storage medium.
I should mention that I am using IIS7.5 on Windows 7. The code will be getting deployed to IIS8 on Win2012. Should anything regarding this answer change, I will update this answer accordingly.
Who likes directly to the point,
In your Config
<appSettings>
<add key="Conf_id" value="71" />
</appSettings>
in your code(c#)
///SET
ConfigurationManager.AppSettings.Set("Conf_id", "whateveryourvalue");
///GET
string conf = ConfigurationManager.AppSettings.Get("Conf_id").ToString();
Try This:
using System;
using System.Configuration;
using System.Web.Configuration;
namespace SampleApplication.WebConfig
{
public partial class webConfigFile : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//Helps to open the Root level web.config file.
Configuration webConfigApp = WebConfigurationManager.OpenWebConfiguration("~");
//Modifying the AppKey from AppValue to AppValue1
webConfigApp.AppSettings.Settings["ConnectionString"].Value = "ConnectionString";
//Save the Modified settings of AppSettings.
webConfigApp.Save();
}
}
}

Resources