I've recently started work on a new project using EpiServer which I am totally new to. One of my tasks requires me to write a custom page provider.
I have got the sample page provider working and loaded. I've also ensured that I have a Enterprise Developer licence as the functionality is only available with this licence.
So I've done a skeleton implementation of my page provider and entered the info into the web.config on my test site exactly as the XmlPageProvider sample does thusly:
<pageProvider>
<providers>
<add entryPoint="26" capabilities="Create,Edit,Delete,Move,MultiLanguage"
name="custom" type="MyWebsite.CustomProvider,CustomPageProvider" />
<!-- <add filePath="~/externalPages.xml" entryPoint="26" capabilities="Create,Edit"
name="xml" type="CodeSamples.XmlPageProvider,XmlPageProvider" />-->
</providers>
</pageProvider>
While we're at it what is the entryPoint property referring to? I cannot find a satisfactory explanation for this anywhere. When I hit the page however I see the following.
Error occured 2/2/2009 10:07:26 AM
User IP fe80::d0e0:16bf:c536:ad4d%10
User Agent Mozilla/4.0 (compatible;
MSIE 7.0; Windows NT 6.0; SLCC1; .NET
CLR 2.0.50727; .NET CLR 3.5.21022;
.NET CLR 3.5.30729; .NET CLR
3.0.30618) Url http://ioc-dev-uk5:17003/cms/admin/default.aspx
Referer (none)
Exception details:
TypeInitializationException: The type
initializer for
'EPiServer.DataFactory' threw an
exception.
Stack trace:
[TypeInitializationException: The type
initializer for
'EPiServer.DataFactory' threw an
exception.] at
EPiServer.Web.InitializationModule.Initialize(EPiServerSection
config, Settings settings,
ConnectionStringSettingsCollection
connectionStringSettings) at
EPiServer.Web.InitializationModule.StaticInitialization()
at
EPiServer.Web.InitializationModule.Application_BeginRequest(Object
sender, EventArgs e) at
System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at
System.Web.HttpApplication.ExecuteStep(IExecutionStep
step, Boolean& completedSynchronously)
[Inner exception ArgumentException:
Cannot create an instance of type
MyWebsite.CustomProvider,CustomPageProvider]
at
EPiServer.Core.PageProviderMap.AddPageProvider(ProviderSettings
pageProviderSetting) at
EPiServer.Core.PageProviderMap.LoadPageProviders(ProviderSettingsCollection
pageProvidersCollection) at
EPiServer.Core.PageProviderMap..ctor(ProviderSettingsCollection
pageProviders) at
EPiServer.DataFactory..cctor()
As you can see this is fairly unhelpful. I've tried getting another licence, resetting IIS, rebooting the box, trying to work out what's going on using reflector to look at the code in the EpiServer DataFactory, all to no avail.
I know it's something really simple but what?! It's been driving me mildly insane for about 2 days now.
Plaese Halp!
Guess I'm answering this myself.
It was really simple.
Went in with reflector and found this:
private void AddPageProvider(ProviderSettings pageProviderSetting)
{
if (Type.GetType(pageProviderSetting.Type) == null)
{
throw new ArgumentException("Cannot create an instance of type " + pageProviderSetting.Type);
}
PageProviderBase pageProvider = this.CreatePageProviderInstance(pageProviderSetting);
pageProvider.Initialize(pageProviderSetting.Name, pageProviderSetting.Parameters);
if (this._pageProviders.ContainsKey(UrlSegment.ReplaceIllegalChars(pageProvider.Name)))
{
throw new ArgumentException(string.Format("There is already a page provider with name {0} registered", pageProvider.Name));
}
this.AddPageProvider(pageProvider, false);
}
The type name required the full namespace on it, so my web.config now looks like:
<pageProvider>
<providers>
<add entryPoint="26" capabilities="Create,Edit,Delete,Move,MultiLanguage"
name="custom" type="MyWebsite.CustomProvider,MyWebsite.CustomProvider.CustomPageProvider" />
</providers>
</pageProvider>
And we're all up and working...
Another example of bad error messaging. It should say "Could not locate type" would have saved a lot of messing about.
Related
I have an MVVM Light infrastructure which is all contained within a Portable Class Library targeting .Net 4, SL5, Win 8, WP 8.1, WPSL 8, Xamarin.Android and Xamarin.iOS. This works perfectly with a WPF client, however, when I try and use it in a Windows Store App/Win 8 environment I am coming up against some resistance. The first issue is found in App.xaml:
<Application
x:Class="Win8Client.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:INPS.Vision.Appointments.Shared.ViewModels"
xmlns:local="using:Win8Client">
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator" />
</Application.Resources>
</Application>
At design time I get "Could not load file or assembly 'Microsoft.Threading.Tasks', version=1.0.12.0 ..." which is referring to my ViewModelLocator. This compiles and appears to run ok but I don't get any design time data. The design time data works fine in the WPF client.
Once running I see my first view but once this line gets called:
Slots = await _appointmentsDataProvider.GetAppointments(SelectedDate);
I get the following exception in the setter of my slots property which takes advantage of MVVM Lights Set method of ViewModelBase. The Slots property is NOT bound to any UI yet.
Exception:
"The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))"
Slots Property:
public List<Slot> Slots
{
get { return _slots; }
set
{
Set(SlotsPropertyName, ref _slots, value); // <-- Exception thrown here
}
}
Realised I haven't actually asked a question. Simply, I would like to know, what is the best approach for using MVVM Light with a Windows Store App?
Thanks in advance for any help or advice!
The first issue "Could not load file or assembly 'Microsoft.Threading.Tasks', version=1.0.12.0 ..." I haven't worked out yet but from time to time I do see the design data. Seems very temperamental...
The second issue - The reason this through me a bit was because is "just worked" in WPF and I assumed it would just work in a Windows Store App. Wrong. It looks like Windows Store Apps handle async/await threading differently - that's my guess.
Fix: Created an IDispatcherHelper interface in PCL with a single method declaration:
void RunOnUIThread(Action action);
Then created a single concrete DispatcherHelper class in each platform specific project (WPF/Windows 8.1) which implement IDispatcherHelper. Each implementation simply calls MVVM Lights:
DispatcherHelper.CheckBeginInvokeOnUI(action);
In App.xaml.cs in the WPF and Windows 8.1 I simply registered the concrete implementations with MVVM Lights SimpleIoc with the IDispatcherHelper as the handle. Within the view model I then use the platform specific implementations through the interface:
var slots = await _appointmentsDataProvider.GetAppointments(SelectedDate);
IDispatcherHelper dispatcherHelper = SimpleIoc.Default.GetInstance<IDispatcherHelper>();
dispatcherHelper.RunOnUIThread(() =>
{
Slots = slots;
});
Got to love abstraction!
I am having issues with serializing objects to JSON, and being new to WCF, I am having issues on where to start in terms of debugging. All I get if I hit the service by typing the url in the browser is page not available.
The scenario: I have class A which inherits a List of class B. If I comment out in Class A where it adds to it's collection, I can at least hit the service (just obviously no data will be present), but if it adds to its collection, I can no longer hit the service.
Interface:
<OperationContract()> _
<WebGet(UriTemplate:="getAdverseReactions", responseFormat:=WebMessageFormat.Json)> _
<ServiceKnownType(GetType(AdverseReactions))> _
<ServiceKnownType(GetType(AdverseReaction))> _
Function GetAdverseReactions() As AdverseReactions
Implementing interface:
Public Function GetAdverseReactions() As AdverseReactions Implements IPortalCoreService.GetAdverseReactions
Return CoreServiceController.GetAdverseReactions()//which returns class A
End Function
Class A:
<CollectionDataContract(Name:="AdverseReactionsCollection", ItemName:="AdverseReaction")> _
Public Class AdverseReactions
Inherits List(Of AdverseReaction)
Class B:
<DataContract(IsReference:=True)> _
Public Class AdverseReaction
I stepped through the code via attaching a process, and no exceptions are thrown and I can confirm that the objects are returned as they should be, I just obviously cannot serialize it. I have read about circular references, and a friend of mine suggested that these two classes might be serializing each other in an infinite manner.
My main question: Is there a place I can look to see why this is occurring, or at least some more information about it? This issue has been handling me, all I want is to serialize this and when I do I think I will take a weeks vacation :).
Add the following block to your web.config <configuration> block
<system.diagnostics>
<sources>
<source name="System.ServiceModel"
switchValue="Information, ActivityTracing"
propagateActivity="true">
<listeners>
<add name="traceListener"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="c:\log\WebTrace.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
and ensure the directory specified (c:\log) exists and is writable by the IIS service.
Once this is done, perform the action that causes the serialization issue then navigate to the directory and double-click the generated svclog file.
This will open the file in the Microsoft Service Trace Viewer. Once this is opened, you will see errors displayed in red down the left-hand side.
Clicking on one of these will show the details in the top right pane and you can click on each of the actions to determine what WCF is complaining about.
While this is slightly dated (2010), I think it will give you some ideas of paths to try.
Quickly finding WCF Serialization/Deserialization Issues
This previous StackOverflow question might help to:
How to trace WCF serialization issues / exceptions
I am attempting to create a db using EF 5 Code First on SQL Server 2008. I can create the db using Integrated Security, but I cannot create the db using a custom user. The code runs the initializer on my home machine for both integrated security and custom user.
The difference in the connection strings is as follows. In addition to these I changed Data Source to Server and Initial Catalog to Database per connectionstrings.com.
<!--<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=MVCTesting;Integrated Security=False;User Id=Green;Password=******" providerName="System.Data.SqlClient" />-->
<add name="DefaultConnection" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=MVCTesting;Integrated Security=True;" providerName="System.Data.SqlClient" />
I compared the SQL users MachineName/LoginName and Green. They both have server roles of public and sysadmin, neither have any user mappings till a db is created then they are mapped to that db.
In global.asax.cs I have
protected void Application_Start()
{
Database.SetInitializer(new MVCTestingInitializer());
//Database.SetInitializer(new DropCreateDatabaseAlways<MVCTestingContext>());
ViewDb();
//Other setup
}
//Init the db by looking up a contact
private void ViewDb()
{
using (var context = new MVCTestingContext())
{
var user = context.Contacts.Where(u => u.FirstName.StartsWith("T"));
var asdf = "";
}
}
And my initializer is ...
public class MVCTestingInitializer : DropCreateDatabaseAlways<MVCTestingContext>
{
protected override sealed void Seed(MVCTestingContext context)
{
//Code to init the db
}
}
Using NLog I am able to verify if the seed is run or not. When I have integrated security it runs, when I do not the seed does not run.
I have also created an account on the machine, added that account to the AppPool and SQL Server, then retested. I still see a failure to connect.
System.Data.SqlClient.SqlException: Login failed for user 'Green'.
In a mad fit I decided to add all possible permissions to the user 'Green', I still see the above error. Does anyone see what I am missing? I am sure it is so simple and I will smack myself in the head afterwards, but I just do not see it.
If I am really far off, please provide the steps to create a SQL Account/Permissions that I can use in my web config and please include app pool setup.
Thanks,
TJ
I will post it as answer :)
If you ever have problem with connecting to db, open ssms and use the same credentials to login to db. This will confirm you have right credentials ;)
I don't see how Windows Azure lets you vary the configuration of an application when you have no choice but to hold configuration settings in web.config (or app.config).
For example...
Quite often projects will make use of a 3rd party library that makes heavy use of web.config. The use of web.config may involve connection strings, app settings or custom configuration sections. A good example of this is ELMAH. A web.config file for ELMAH might look like the following:
<configuration>
<configSections>
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
</sectionGroup>
</configSections>
<connectionStrings>
<add
name="MyElmahDatabase"
providerName="System.Data.SqlClient"
connectionString="Server=tcp:myServer.database.windows.net,1433;Database=myDB;User ID=user#myServer;Password=password;Trusted_Connection=False;Encrypt=True;Connection Timeout=30" />
</connectionStrings>
<elmah>
<security allowRemoteAccess="1" />
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="MyElmahDatabase" />
</elmah>
</configuration>
There are a couple of problems here:
There is no way for me to update or vary whether remote access is enabled between Service Configurations.
There is no way for me to update or vary the ELMAH connection string between Service Configurations.
This is because the web.config is packaged as is into the .cspkg file and ELMAH will not look at the Service Configuration settings (which are the only way I can vary configuration settings between Service Configurations).
I can think of many other examples where this is a problem...
Any data access frameworks that look directly at the connection strings section.
Any custom configuration settings I need to create.
...to name just two.
Am I missing something or is this a significant gap in the configuration management offered by Windows Azure?
EDIT
From the answer and comments below, it looks like this is something that is not well supported. I think that managing multiple solution build configurations to support different configuration profiles is a very weak solution. I should not have to rebuild the solution for each configuration profile I need (there will likely be quite a few). Compilation is not equal to configuration.
I was wondering if there was a way to modify the .cspkg file as it is just a zip file. According to this documentation you can on Linux.
I've looked at the manifest in the .cspkg file and it looks like this:
<PackageManifest version="2">
<Encryption keytype="1" />
<Contents hashtype="1">
<Item name="MyApp.Web.UI_<GUID>.cssx" hash="AED69299C5F89E060876BC16BD3D6DE5130F6E62FFD2B752BAF293435339B7E2" uri="/MyApp.Web.UI_<GUID>.cssx" />
<Item name="MyApp.Web.Services_<GUID>.cssx" hash="7AC81AFF642E4345173C8470C32A41118A4E3CFD4185B82D0ADA44B71057192D" uri="/MyApp.Web.Services_<GUID>.cssx" />
<Item name="SMPackage_<GUID>.csmx" hash="B5E6B83B62AF64C7C11CAC1A394ABBF15D7DB7667A773C5284CE5BE95C5834E9" uri="/SMPackage_<GUID>.csmx" />
<Item name="SDPackage_<GUID>.csdx" hash="F34B7C02A551D82BAD96881E2DA9447D0014D49B47CCB3840475BDC575234A7D" uri="/SDPackage_<GUID>.csdx" />
<Item name="NamedStreamPackage_<GUID>.csnsx" hash="FA2B5829FF5D9B2D69DCDDB0E5BDEE6B8B0BC09FFBF37DAEEE41CF3F3F4D0132" uri="/NamedStreamPackage_<GUID>.csnsx" />
</Contents>
<NamedStreams>
<Stream name="RequiredFeatures/MyApp.Web.Services/1.0" />
<Stream name="RequiredFeatures/MyApp.Web.UI/1.0" />
<Stream name="SupportData/MyApp.Web.Services/1.0" />
<Stream name="SupportData/MyApp.Web.UI/1.0" />
</NamedStreams>
</PackageManifest>
Unfortunately, if I re-compute the hash of the unchanged "MyApp.Web.UI_.cssx" file, my hash is different from the one in the manifest.
Hash from manifest: AED69299C5F89E060876BC16BD3D6DE5130F6E62FFD2B752BAF293435339B7E2
My calculated hash: E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
Note that I have not yet changed the file, so the hash should be the same.
This suggests I'm calculating it wrong. My method was as follows:
class Program
{
static void Main(string[] args)
{
using (FileStream fs = new FileStream(args[0], FileMode.Open))
{
ComputeHash(new SHA256Managed(), fs);
}
}
private static void ComputeHash(HashAlgorithm hashAlgorithm, Stream stream)
{
byte[] hash = hashAlgorithm.ComputeHash(stream);
string hashString = BitConverter.ToString(hash);
Console.WriteLine(hashString.Replace("-", string.Empty));
Console.WriteLine();
}
}
The documentation link above, suggests it is straightforward to re-calculate the hash (on Linux anyway).
Does anyone know how to re-compute the hashes?
Passing a Stream to ComputeHash() ends up with a different hash as compared to using the byte[] overload. I don't know why.
Try something like:
private static void ComputeHash(HashAlgorithm hashAlgorithm, Stream stream)
{
BinaryReader reader = new BinaryReader(stream)
byte[] hash = hashAlgorithm.ComputeHash( reader.ReadBytes( (int)stream.Length ) );
string hashString = BitConverter.ToString(hash);
Console.WriteLine(hashString.Replace("-", string.Empty));
Console.WriteLine();
}
This will give you the hash you're after.
As you've probably already discovered, on linux you can get the digest with
openssl dgst -sha256 /path/to/file
I you have items in your web.config that you want to change depending on how it's being built, there is a solution that is outside of Azure that you can use. You can use Web.config transforms. These transforms are tied to your build configuration not your service configuration, but your service configurations a likely closely tied to your build configurations anyway (...Local.csfg -> Debug, ...Cloud.csfg -> Release). If the default build configurations don't work for you, just create the ones you need.
If you want to use different service definitions per service configuration, then it's not supported by the UI, but you can mess around with the build process to make it work
I setup MiniProfiler.MVC3 - 1.7 package in my project yesterday. The Controller and view profiling is working fine, but the peice I'm really interested in is the SQL Profiling. I have not been able to get this to work. I'm using EF Code First with a SQL 2008 database.
I have followed all the suggestions in this post ..
mvcminiprofiler-on-ef-4-1-code-first-project-doesnt-profile-sql
In the miniprofiler.cs i have my SQL connection setup as...
var factory = new SqlConnectionFactory(ConfigurationManager.ConnectionStrings["CMDBMVC3"].ConnectionString);
My Web.config db connection is...
<add name="CMDBMVC3" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI; AttachDBFilename=|DataDirectory|CMDB_MVC3.mdf;Initial Catalog=CMDB_MVC3;Trusted_Connection=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
If I put a breakpoint on the mini-profiler line it points to the correct db connection. I'm not sure what else to do at this point. I would appreciate any direction on how to get the SQL profiling working.
I use EF Code first and the mini profiler within my Context constructor I create a new connection factory and pass this to the ProfiledDbConnectionFactory method this returns a profiled connection that you can then set as the DefaultConnectionFactory of the context.
public MyConext()
{
var factory = new ConnectionFactory();
var profiled = new MvcMiniProfiler.Data.ProfiledDbConnectionFactory(factory);
Database.DefaultConnectionFactory = profiled;
}
The connection Facotry just returns a new sql connection
public class ConnectionFactory :IDbConnectionFactory
{
public DbConnection CreateConnection()
{
var cnn = new System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings["SomeConnection"].ToString());
return cnn;
}
You also need to add the ProfiledDBProvider to the web config file. Make sure the version number is correct for you.
<system.data>
<DbProviderFactories>
<remove invariant="MvcMiniProfiler.Data.ProfiledDbProvider" />
<add name="MvcMiniProfiler.Data.ProfiledDbProvider" invariant="MvcMiniProfiler.Data.ProfiledDbProvider"
description="MvcMiniProfiler.Data.ProfiledDbProvider"
type="MvcMiniProfiler.Data.ProfiledDbProviderFactory, MvcMiniProfiler, Version=1.7.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3" />
</DbProviderFactories>
</system.data>
This works fine for me in both MVC and asp.net webforms using the Miniprofiler nuget package. I'd also check out the new MVC version of the nuget package that auto configs profiling as part of a global action filter.