How to publish Silverlight site using a domain service? - c#

I have a Visual Studio 2010 solution with 2 projects. One is a Silverlight client, the other a web site to which I added a domain service. It works fine when debugging in Cassini, but when I publish to IIS I get nothing returned from my entity query.
I'm not even sure where to start as this is my first attempt at doing this.

A few things:
Developing on Cassini (don't do it if you can avoid it)
It's always better to develop against IIS itself. There are differences between IIS and Cassini which can bite you if you aren't aware of them and it just makes more sense; you should always develop as close to the environment that you are develping for. Unless you are deploying to Cassini (and you aren't, no one does) then there's no point in developing against it unless you simply can't (you don't have a local install of IIS).
Web Deploy
Install Web Deploy on the IIS server you are going to deploy to. Once you do that, you can right click the web/domain project in your solution and select "Build Deployment Package".
Then, you will get a package that you can use with Web Deploy which will deploy everything (Silverlight, ASP.NET components, etc, etc) your project to IIS with a simple command-line call.

This was a very stupid, newbie issue. I used SQL Server Profiler to watch the queries come in and realized the account being used to authenticate against SQL Server was the server's computer account. I secured the Domain Service's methods and allowed the computer account access tot he DB.

Deploying to IIS might have some issues. I'd like to see what errors messages you're getting. Without these information it will become pretty difficult to give you an advice.
PS: I'm gonna assume that your WCF RIA services have valid definition ;-).
Based on my experience, this is the minimum config file, but it certainly will require more settings if you're consuming Authentication Domain Services or Data domain services (such as LinqToEntities or LinqToSql domain services):
Make sure your IIS have all the sections required by WCF RIA
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.serviceModel">
<section name="domainServices" type="System.ServiceModel.DomainServices.Hosting.DomainServicesSection, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" allowDefinition="MachineToApplication" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web>
<!-- You might need identify tag if you app requires additional permission to run -->
<!-- See you want to see more details when a error happens -->
<customErrors mode="Off"/>
<compilation debug="true" targetFramework="4.0" />
<!-- If your application uses authentication and authoriztion then -->
<!-- Elements required required for authentication: authentication and membership and probably roleManager -->
<httpModules>
<add name="DomainServiceModule" type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</httpModules>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<add name="DomainServiceModule" preCondition="managedHandler"
type="System.ServiceModel.DomainServices.Hosting.DomainServiceHttpModule, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</modules>
</system.webServer>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
Make sure the WCF RIA services are up and runnning
Try to access the WCF RIA service by using a web browser. Usually the service you're exposing has format like:
http://[hostname]/[namespacename]-[classname].svc
So, you should be able to hit the URL and see an output like:
Make sure DLLS are available
There are two options to deploy the WCF RIA dlls in the server side. You can indicate to the application that DLLs should be copied into the bin folder of your application or you can run the WCF RIA installer in server mode.
Accessing the services from the client
If the services are up and running they should be reachable to your Silverlight client. If there is an error you can start tracing by enabling WCF RIA debugging.
See http://blogs.msdn.com/b/saurabh/archive/2010/03/16/ria-services-application-deployment.aspx for more details about it.

Related

Azure WebApp How to Get a Useful 500 error

I searched previous questions, first, but could not find anything that solved my issue. I have a Web App project that works fine locally, then fails with 500 after having been published. This is my first time using any of the Microsoft stack (C#, ASP.NET MVC, Azure), so bear with me.
Visual Studio 2015 Community
.NET 4.5 / ASP.NET 5 Web App project
StackExchange.Redis / Fleck / React.AspNET NuGet packages
I have added the following to web.config:
<system.web>
<customErrors mode="Off"/>
</system.web>
<system.webServer>
...
<httpErrors errorMode="Detailed" />
<tracing>
<traceFailedRequests />
</tracing>
</system.webServer>
I also turned on detailed error messages under the web app's settings using the Server Explorer view in Visual Studio (right-click the app's name, click settings). I also attempted to remotely debug the web app, but received an "access is denied"("Remote debugging does not work in Express editions of Visual Studio" maybe?). So, I'll post the web.config from the Azure web app.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<customErrors mode="Off"></customErrors>
</system.web>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/>
</handlers>
<httpErrors errorMode="Detailed" />
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false" startupTimeLimit="3600"/>
<tracing>
<traceFailedRequests />
</tracing>
</system.webServer>
</configuration>
One or a combination of these changes mentioned above worked in providing a more useful error screen.
If someone can come along and post an answer as to which step(s) it may have been and why, etc. I'd be glad to accept it. I don't want to post an answer, as I honestly don't know which 'fixed' it.
Yes, the customErrors element belongs under system.web
The most common error people make when first deploying to Azure or any other server is to properly set connection strings for that environment, so I would start by checking those.
You mention ASP.NET 5 Web App project so this means you have a Startup.cs file, right?
Check in your project.json file if you have (if not add it) the Microsoft.AspNet.Diagnostics package.
Then add on the public void Configure handler:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseDeveloperExceptionPage();
//other app.Uses
}
This is intended for local dev because it will show the detailed full error, you might want to later add it in an if:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
Source: docs.asp.net

Deploy REST service without access to IIS

I have developed a .NET REST web service in C#. While I have plenty of C# experience, I unfortunately do not have much understanding in deploying such a service in a web hosting environment.
Due to the environment, I do NOT have access to IIS.
The advice I have been provided with by the support services of the hosting provider is as follows:
Create a subdomain of the main domain to achieve a dedicated application pool (this a requirement of the host provider)
Create a Bin folder to hold my compiled libraries of source code
Add the following to the Web.Config file:
<system.web>
<httpHandlers>
<add type="ReportRESTWebService.Service, ReportRESTWebService" verb="*" path="report" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add name="report" path="report" verb="*" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" resourceType="File" requireAccess="Script" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
</handlers>
<directoryBrowse enabled="false" />
</system.webServer>
The above would have the effect of creating a handler mapping for the report resource on all HTTP verbs and forwarding any HTTP traffic on that resource to my ReportRESTWebService.dll for handling.
The point I am unclear on is whether the above will be satisfactory and how do I test whether the advice I am given is correct. I know that I have the site running locally but I have access to IIS so I have control over the configuration.
Hopefully somebody can help.
Thanks
If you are using Wcf Rest,then you can probably consider hosting it as as windows service
or self hosted service.
Windows Service
http://blogs.msdn.com/b/juveriak/archive/2009/03/15/rest-endpoint-hosted-in-a-wcf-windows-service.aspx
Self hosted Service
http://www.c-sharpcorner.com/uploadfile/dhananjaycoder/self-hosted-wcf-rest-service-or-hosting-wcf-rest-service-in-console-application/
It would seem, after a day of exhaustive testing, that the steps I had taken (detailed in the question) would be satisfactory.
One point to watch out for is the matching Managed Pipeline Mode for your application pool. Failure to match this up correctly with your Web.Config will result in pain.

not able to test asp.net web service from remote machine

we have built a asp.net web service application that we test on the local machine.
We have deployed it on the client's server and tested it there as well.
The web service returns JSON data, not xml.
But when the we try to access that URL from a remote machine, we cannot see the input fields for taking the parameters. it shows the list of the methods in the web service but when we click on them there's no text fields for input.
We'd like to access the web services remotely and test them.
Any help would be appreciated.
You'll want to make sure you have the following in your config file.
<configuration>
<system.web>
<webServices>
<protocols>
<add name="HttpGet"/>
<add name="HttpPost"/>
</protocols>
</webServices>
</system.web>
Really though you should probably be using something like SoapUI for testing services as the tests are re-runnable ect.

Connect client application services to a custom DB (not the default CE DB)

I have an existing C# ASP.NET web application which uses the membership and role providers. The tables for these are hosted in the same DB which holds all of the application tables (hosted in Azure for production, local SQLExpress for dev).
I would like to write a console application which uses the same user and role information. To this end I have enable client application services (on the console app) and added a new web service which exposes these to the console app.
I can get this working in a test setup (both as console and winforms), i.e. with the web service creating its own blank set of users/roles which from what I've read are stored in a local file as a SQL CE database.
How can I get the web service to be reading from my application's DB?
Relevent web.config for original web application:
<profile defaultProvider="DefaultProfileProvider">
<providers>
<add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="SecondBiteDBContext" applicationName="/" />
</providers>
</profile>
<membership defaultProvider="DefaultMembershipProvider">
<providers>
<add name="DefaultMembershipProvider" type="System.Web.Providers.DefaultMembershipProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="SecondBiteDBContext" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="10" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" />
</providers>
</membership>
<roleManager defaultProvider="DefaultRoleProvider" enabled="true">
<providers>
<add name="DefaultRoleProvider" type="System.Web.Providers.DefaultRoleProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="SecondBiteDBContext" applicationName="/" />
</providers>
</roleManager>
Web.config for the web service:
<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true" requireSSL="false" />
<profileService enabled="true" readAccessProperties="WebSettingsTestText" writeAccessProperties="WebSettingsTestText" />
<roleService enabled="true"/>
</webServices>
</scripting>
</system.web.extensions>
....
<system.web>
<profile enabled="true" >
<properties>
<add name="WebSettingsTestText" type="string"
readOnly="false" defaultValue="DefaultText"
serializeAs="String" allowAnonymous="false" />
</properties>
</profile>
</system.web>
App.config for console app:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<appSettings>
<add key="ClientSettingsProvider.ServiceUri" value="http://localhost:31337/SecondBiteAppServices/Profile_JSON_AppService.axd" />
<add key="ClientSettingsProvider.ConnectionStringName" value="DefaultConnection" />
</appSettings>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=.\SQLExpress;Initial Catalog=SBAuto;MultipleActiveResultSets=True;Integrated Security=SSPI" />
</connectionStrings>
<system.web>
<membership defaultProvider="ClientAuthenticationMembershipProvider">
<providers>
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="http://localhost:31337/SecondBiteAppServices/Authentication_JSON_AppService.axd" connectionStringName="DefaultConnection" savePasswordHashLocally="False" />
</providers>
</membership>
<roleManager defaultProvider="ClientRoleProvider" enabled="true">
<providers>
<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="http://localhost:31337/SecondBiteAppServices/Role_JSON_AppService.axd" cacheTimeout="86400" connectionStringName="DefaultConnection" />
</providers>
</roleManager>
</system.web>
</configuration>
I haven't specified the optional credentials provider, because I'm not using a form - right now I can't get a hard coded call to validateuser() to succeed.
Using project properties -> services tab -> advanced button, I've specified a custom connection string pointing to the required DB. I know it is connecting to my DB, because for a while I was getting exceptions about "invalid object ApplicationProperties". Creating a table in my DB with columns PropertyName and PropertyValue fixed this. Note that I had already run aspnet_regsql on my DB which I would expect should have created the required tables.
However it is not passing validation checks on the users residing in that DB - it runs cleanly (no exceptions) but fails the login. Based on the structure of app.config above, I speculate that the custom connection string is only applying to the profile service, not the membership or role services? (Only the profile service [client settings provider] is taking the connection string as a param.) EDIT: Looking back at some docs, http://msdn.microsoft.com/en-us/library/bb384312 seems to indicate this custom connection string is only for storing the offline local cache stuff.
Using project -> asp.net configuration (with the web service project selected), the web site admin tool doesn't let me do anything meaningful to configure the providers or add new ones.
I haven't been able to track down anything that will let me actually use the users and roles in that DB. Any ideas? (I am fairly new to .net, so it is quite possible I'm missing something, but I've been having a lot of trouble with the documentation and getting any decent results out of google.)
Once this is working, I want to share business logic between the various projects. Currently the logic is located in the main web app controller methods - obviously I will need to refactor that out to a shared layer. Will that be possible given the objects involved are based on entity framework?
I did a trial refactor before I started with all of this client services stuff. I was able to get everything referenced and compiling but the code was failing silently very early in execution, my best guess was that all of the various framework related stuff was not initialized properly - hence entering into client app services. However I'm worried that even if I get CAS going, entity framework is going to still cause issues.
Last one: how can I share config elements (connection strings mostly) between config files in different projects? Would like to be able to swap between dev and production without having to edit multiple files.
EDIT: How much of a hack is doing something like this? http://devpinoy.org/blogs/comgen/archive/2007/08/15/use-membership-api-in-winforms.aspx
That's the only actually useful thing I've been able to find, even if not directly related to CAS. It seems like I could just copy the appropriate lines form my main web app web.config (which include a link to my DB's connection string).
Thanks!
Update 25/1/13: Tried the alternative suggested on the edited in link just above, substiting in the web.config elements listed above (although I also had to copy the system.web.providers.dll manually to the bin/debug dir). I can cleanly call validateuser(), but it still won't allow the login. I know I'm hitting my DB because activity is occurring in SQL profiler, and the last activity timestamp on the user table is being updated. This doesn't occur when doing it the CAS way.
Update 25/1/13 #2 - Just spent the past 4 hours trying to debug why it is failing, and its driving me insane fast. By reading the code (not debugging) all I can tell is that it is failing on comparing the provided password hash with the stored one. I'm 100% sure I'm providing the correct user and password.
Microsoft hasn't published the code for system.web.providers.dll, so debugging wise I can't step into anything beyond the membership.validateuser call since that calls DefaultMembershipProvider.ValidateUser.
Resharper will show me the soure code of DefaultMembershipProvider (by decompiling it) but I can't get it to debug into it. I've read elsewhere that you can decompile the whole dll to a project, remove the reference to the dll and then add the project.
Attemping to do so, I've had the following problems:
Dis# allows me to save the lot as project, but it produces seemingly managled source full of a lot of errors. They seem to be mostly syntax errors around where it hasn't got the variable names right. When importing the project VS warns about changing the target .net version, but this doesn't seem to do anything
Telerik JustDecompile lets me save the project, but it didn't include the .cs file that compliments system.web.providers.resources.providerresources.resx. I imported the .cs from Dis# which works. However it is still full of errors, but different ones (still a few syntax related though) and not so many. A fair number of them have something to do with classes in other system.x namespaces. Blanket adding the lot as references didn't help anything.
ILSpy - when opening the dll, it lists the portions of the other namespaces that the JustDecompile project seems to be referencing. But it only lets me save the files one by one and I'm not really interested in trying to rebuild the structure of several dozen dll files by hand...
This is my first attempt at decompiling anything, but everything I can find seems to be indicating what I'm doing should work (but they certainly didn't mention any of the problems I've been having). Any ideas of what to do next?
Side note relating to my attempted web service in the OP: I noticed that aspnet_regsql.exe created a duplicate set of membership and role tables prefixed by "aspnet_". E.g. aspnet_membership whilst my existing app/code uses just plain membership. That clears up why the web service wouldn't read my data, as it was checking different tables.
I found a blog (can't find the link again right now) about someone who wrote some code to migrate their data between the two schemas which indicated that the different sets of tables are related to different versions of the membership (etc) providers. So I'm assuming that the providers as seen in the "universal providers (system.web.providers) are different (and imcompatible) with the providers used in client application services and exposed by the web service I created.
Providing an answer to hopefully spare some others a lot of pain. I don't have the answers to all of the questions I asked above, but there is useful information here.
To make the universal providers (system.web.providers.dll) connect to any DB, simply use the relevant config lines from my first web.config snippet above. This works in app.config (etc) for any type of .NET project (as far as the ones I've tried). Make sure you add a reference to the dll, and that the connection string is included in the config. I refactored the connection strings to a separate config which I linked to each project, to avoid duplication of details.
The old style providers are incompatible with the new universal providers, because their SQL schema is different. It is possible to convert from old to new ones by writing some scripts to transform between schema.
BUT there are issues with the hash algorithm used to validate logins when switching between them like this. You need to force SHA1 on e.g. <membership defaultProvider="DefaultMembershipProvider" hashAlgorithmType="SHA1"> when trying to use these providers outside of a web application.
This is why my ValidateUser() calls that I was asking about were failing. This bug on Connect is relevant: http://connect.microsoft.com/VisualStudio/feedback/details/734341/system-web-providers-defaultmembershipprovider-behavior-differs-from-sqlmembershipprovider-when-dealing-with-password-compatibility . Because of this bug, my web app (using universal providers) has been running in SHA1 mode since the start - it should have been HMACSHA256. The default HMACSHA256 was correctly applying when using the console app hence the mismatch!
Someone else who had issues with hash algorithm configuration: http://chriskinsmanblog.azurewebsites.net/2012/03/30/SystemWebProvidersDefaultMembershipProviderBehaviorChange.aspx
However after all of the above, I discovered that you don't necessarily need to be using these providers. It is possible to get the entity framework to execute correctly without being logged in or having any reference to the providers. (I wish I knew why I couldn't get it work before I started all this mess. I know I had the relevant dlls referenced.)
I still have no idea why I couldn't satisfactorily recompile web.providers.dll.

dynamically set WCF baseAddressPrefixFilters

I have a WCF service that I am deploying in a shared hosting environment. Because of this I have to specify baseAddressPrefixFilters (see answer here for why this is necessary). Setting the base address prefix filters happens in the web.config like so...
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
<add prefix="http://example.com"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
The problem is that I have multiple environments that are configured this way with their own urls (i.e. dev, test, prod)
I tried the following with no luck...
<serviceHostingEnvironment>
<baseAddressPrefixFilters>
<add prefix="http://dev.example.com"/>
<add prefix="http://test.example.com"/>
<add prefix="http://example.com"/>
</baseAddressPrefixFilters>
</serviceHostingEnvironment>
So the question is how do I set the baseAddressPrefixFilter dynamically at runtime?
If you are running under IIS7, this is a good walk through of the problem and solution. If not, the information for the WCF side is still what you need to know to resolve your issues.
http://keithelder.net/2008/04/28/configuring-wcf-and-iis-7-with-http-bindings-and-multiple/
Have you looked at the ServiceHostFactory? We used this in our 3.0 services to work with the different host headers.
http://blogs.msdn.com/rampo/archive/2007/06/15/supporting-multiple-iis-bindings-per-site.aspx

Categories

Resources