I´m having a problem to create new assets using REST API in Fatwire. I can connected to read and update assets, but to create I´m receiving a error message.
Could you help me?
I´m receiving a error:
" PUT http://localfw.com.br:8080/cs/REST/sites/MySite/types/FD_Ajuda_C/assets/0?multiticket=ST-30-i3DZmlFcbbNNsdK0IwE0-cas-.com.br-1 returned a response status of 500"
Below my source code:
package com.fatwire.rest.samples.flex;
import java.sql.Date;
import javax.ws.rs.core.MediaType;
import com.fatwire.rest.beans.AssetBean;
import com.fatwire.rest.beans.Association;
import com.fatwire.rest.beans.Associations;
import com.fatwire.rest.beans.Attribute;
import com.fatwire.rest.beans.Parent;
import com.fatwire.rest.beans.Attribute.Data;
import com.fatwire.rest.beans.Blob;
import com.fatwire.wem.sso.SSO;
import com.fatwire.wem.sso.SSOException;
import com.fatwire.wem.sso.SSOSession;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.UniformInterfaceException;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.WebResource.Builder;
public final class CreateAsset
{
public static void main(String[] args)
{
// Step 1: Initiate Jersey client
Client client = Client.create();
// Step 2: Create a WebResource with the base URL
WebResource webResource =
client.resource("http://localfw.com.br:8080/cs/REST/");
// Step 3: Authenticate over SSO-CAS to acquire a ticket specific to a
// service or a multi-ticket over multiple services.
SSOSession ssoSession = null;
String multiticket = null;
try
{
ssoSession = SSO.getSSOSession("ExampleCASConfig.xml");
multiticket = ssoSession.getMultiTicket("user", "pss");
}
catch (SSOException e)
{
e.printStackTrace();
}
// Step 4: Provide the ticket into the REST request
webResource = webResource.queryParam("multiticket", multiticket);
// Trying to create a Flex asset for the Flex asset type
String flexAssetSiteName = "FolhaDirigida";
String flexAssetTypeName = "FD_Ajuda_C";
// Step 5: Specify the REST Resource URL into the WebResource
// For creating assets of type {typename} in the CS site {sitename},
// this is: {base_url}/sites/{sitename}/types/{typename}/assets/0
webResource =
webResource.path("sites").path(flexAssetSiteName).path("types")
.path(flexAssetTypeName).path("assets").path("0");
// Step 6: Create a Builder and set the desired response type
// Supported response types are:
// MediaType.APPLICATION_XML, or,
// MediaType.APPLICATION_JSON
Builder builder = webResource.accept(MediaType.APPLICATION_XML);
// Step 7: Instantiate and define the AssetBean for the asset
AssetBean sourceAsset = new AssetBean();
// Name - mandatory field
sourceAsset.setName("Test REST API FD_Ajuda_C");
//sourceAsset.setId("1307037035763");
// Description - optional field
sourceAsset.setDescription("Test FD_Ajuda_C description");
// Add attributes / associations / parents as in the Asset type
// definition
Attribute sourceAssetAttribute = new Attribute();
Data sourceAssetAttributeData = new Data();
sourceAssetAttribute.setName("titulo");
sourceAssetAttributeData.setStringValue("Test Título FD_Ajuda_C");
sourceAssetAttribute.setData(sourceAssetAttributeData);
sourceAsset.getAttributes().add(sourceAssetAttribute);
sourceAssetAttribute = new Attribute();
sourceAssetAttributeData = new Data();
sourceAssetAttribute.setName("conteudo");
sourceAssetAttributeData.setStringValue("Test Long Description FD_Ajuda_C");
sourceAssetAttribute.setData(sourceAssetAttributeData);
sourceAsset.getAttributes().add(sourceAssetAttribute);
sourceAssetAttribute = new Attribute();
sourceAssetAttributeData = new Data();
sourceAssetAttribute.setName("indAtivo");
sourceAssetAttributeData.setStringValue("FD_IndAtivo_C:1307036912210");
sourceAssetAttribute.setData(sourceAssetAttributeData);
sourceAsset.getAttributes().add(sourceAssetAttribute);
Parent parent = new Parent();
parent.setParentDefName("CategoriaAjuda");
parent.getAssets().add("FD_Conteudo_P:1307036837080");
sourceAsset.getParents().add(parent);
// Required: Must specify the site(s) for the asset
sourceAsset.getPublists().add(flexAssetSiteName);
try{
// Step 8: Invoke the REST request to create the asset
AssetBean resultAsset = builder.put(AssetBean.class, sourceAsset);
}
catch (UniformInterfaceException e) {
// TODO: handle exception
System.out.println("Teste" + e.getResponse());
System.out.println(" || sourceAsset: " + sourceAsset.toString());
}
// If the REST call encounter a server side exception, the client
// receives a UniformInterfaceException at runtime.
// Troubleshooting UniformInterfaceException
// =========================================
//
// Cause: HTTP 403: User does not have permission to access the REST
// resource.
// Remedy: Use an authorized CAS user to use this REST resource.
//
// Cause: HTTP 404: Either site and/or asset type does not exist, or the
// asset type is not enabled in the site.
// Remedy: Verify existence of the site and/or asset type, if necessary
// create the site and/or type and make sure that the type is enabled in
// the site.
//
// Cause: HTTP 500: Generic server side exception.
// Remedy: Verify that the source AssetBean has been provided with all
// mandatory attributes, associations as per type definition, verify
// that at least one site has been provided in the publist attribute of
// the AssetBean.
//
// Cause: UnmarshalException.
// Remedy: Verify that the correct bean has been provided in the
// argument for put().
}
}
Verify that the source AssetBean has been provided with all
mandatory attributes, associations as per type definition
Verify that at least one site has been provided in the publist attribute of
the AssetBean
Related
I'm trying to access the Watson Text to Speech API thru an action script 3 flash application. As you known Adobe implement a new security features to restrict the access across domains using a mechanism that use a rules based xml configuration file (crossdomain.xml). In my case the below error is raised when the script is executed:
Source code:
package
{
import flash.net.URLRequest;
import flash.net.URLRequestHeader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLLoader;
import flash.net.URLVariables;
import flash.net.URLRequestMethod;
import flash.events.Event;
import flash.events.HTTPStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.events.IOErrorEvent;
public class Greeter
{
public function sayHello():String
{
var params:Object = {user:"John",password:"secret"};
var request:URLRequest = new URLRequest();
request.url = "https://watson-api-explorer.mybluemix.net/text-to-speech/api/v1/voices";
request.contentType = "application/json";
request.method = URLRequestMethod.POST;
request.data = JSON.stringify(params);
var contentTypeHeader:URLRequestHeader = new URLRequestHeader("Content-Type","application/json");
var acceptHeader:URLRequestHeader = new URLRequestHeader("Accept","application/json");
var formDataHeader:URLRequestHeader = new URLRequestHeader("Content-Type","application/json");
var authorizationHeader:URLRequestHeader = new URLRequestHeader("Authorization","Basic YjcxYWUwNTMtZTJmYi00ZmQzLWFiMTctOTRjYTc2MzYzYWE3OlZ5dU9VZ0w3ak1zVw==");
request.requestHeaders = [acceptHeader,formDataHeader,authorizationHeader,contentTypeHeader];
var postLoader:URLLoader = new URLLoader();
postLoader.dataFormat = URLLoaderDataFormat.BINARY;
postLoader.addEventListener(Event.COMPLETE, loaderCompleteHandler);
postLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
postLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
postLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
try
{
postLoader.load(request);
}
catch (error:Error)
{
trace("Unable to load post URL");
}
var greeting:String;
greeting = "Prueba de conexión a Watson!";
return JSON.stringify(request.data);
}
private function loaderCompleteHandler(event:Event):void
{
trace("loaderCompleteHandler: ");
}
private function httpStatusHandler(event:HTTPStatusEvent):void
{
trace("httpStatusHandler: ");
}
private function securityErrorHandler(event:SecurityErrorEvent):void
{
trace("securityErrorHandler: " + event);
}
private function ioErrorHandler(event:IOErrorEvent):void
{
trace("ioErrorHandler: " + event);
}
}
}
Console output:
[trace] Advertencia: Error al cargar el archivo de política desde https://watson-api-explorer.mybluemix.net/crossdomain.xml
[trace] *** Violación de la seguridad Sandbox ***
[trace] Se ha detenido la conexión con https://watson-api-explorer.mybluemix.net/text-to-speech/api/v1/voices - no se permite desde http://garragames.com/garra-x/Tick.swf
[trace] 05:45:44 PM | err | [SecurityErrorEvent type="securityError" bubbles=false cancelable=false eventPhase=2 text="Error #2170: Security sandbox violation: http://garragames.com/garra-x/Tick.swf cannot send HTTP headers to https://watson-api-explorer.mybluemix.net/text-to-speech/api/v1/voices."]
[trace] Error #2044: Unhandled securityError:. text=Error #2170: Security sandbox violation: http://garragames.com/garra-x/Tick.swf cannot send HTTP headers to https://watson-api-explorer.mybluemix.net/text-to-speech/api/v1/voices.
¿Exist another option to access the API from Action Script Flash App?
Your real question should be "how to authenticate?" with Watson API from Flash rather than how to beat that security sandbox issue of loading/decoding via URLLoader (which has automatic cross-domain check).
You have to authenticate (log in) somehow. This seems an unlikely thing to achieve via Actionscript only. You can see a Flash Player error like :
"Authorization header cannot be sent using Actionscript"
by using URLStream instead URLLoader. Also URLStream does not care about security issues. It just gets the bytes if they exist. According to this document it says Flash "Authorization" requests are allowed. Did not work for me though. Maybe it's not allowed in debugger?
Once authenticated from your URL/Domain, then also your Flash app can make any requests as normal POST url since it's asking via same (now allowed) domain. Use URLStream instead of URLLoader if you want bytes since it has no cross-domain restrictions.
PS: for example, you can use a Sound object to playback text converted into speech.
(if authenticated, ie: you are logged in) Try :
Make an input text box on stage, with instance name txtbox.
Save below code in document class called : Main.as (compile as Main.swf)
Test the code below : (SWF result = type into textbox and press enter to hear it spoken).
package
{
import flash.display.MovieClip;
import flash.utils.*;
import flash.media.*;
import flash.net.*;
import flash.events.*;
public class Main extends MovieClip
{
public var snd_Obj: Sound = new Sound;
public var snd_Chann: SoundChannel = new SoundChannel;
public var snd_req: URLRequest = new URLRequest();
public var str_Token: String = "";
public var url_sendto_Watson: String = "";
public var str: String = "";
public var str_Voice: String = "";
public var str_mySpeech: String = "";
public var load_Token: URLLoader;
public function Main()
{
load_Token = new URLLoader();
load_Token.addEventListener(Event.COMPLETE, onTokenLoaded);
load_Token.load(new URLRequest("https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/text-to-speech/api"));
//# Your token as requested from :: https://stream.watsonplatform.net/authorization/api/v1/token?url=https://stream.watsonplatform.net/text-to-speech/api
//trace("Token : " + str_Token); //# To confirm it has token code
//txtbox.type = "INPUT";
txtbox.background = true;
txtbox.text = ""; //starting text
txtbox.addEventListener(TextEvent.TEXT_INPUT, text_inputCapture);
txtbox.addEventListener(KeyboardEvent.KEY_DOWN, key_handler);
addChild(txtbox);
}
function key_handler(evt:KeyboardEvent)
{
if(evt.charCode == 13) //# if ENTER key is pressed (will send text to convert to speech)
{
str_mySpeech = txtbox.text;
str_mySpeech = str_mySpeech.replace(" ", "%20");
str_Voice = "en-US_AllisonVoice"; //or your preferred voice (see:
//# Update requested URL to include your typed text
url_sendto_Watson = ""; //# reset
url_sendto_Watson = "https://stream.watsonplatform.net/text-to-speech/api/v1/synthesize?";
url_sendto_Watson += "accept=audio/mp3"; //# get as MP3 result
url_sendto_Watson += "&text=" + str_mySpeech;
url_sendto_Watson += "&voice=" + str_Voice; //# ie: "en-US_AllisonVoice"
url_sendto_Watson += "&token=" + str_Token;
//# Attempt loading
snd_req.url = url_sendto_Watson;
snd_Obj = new Sound();
snd_Obj.addEventListener(Event.COMPLETE, onSoundLoaded);
snd_Obj.load( snd_req );
txtbox.removeEventListener(KeyboardEvent.KEY_DOWN, key_handler);
}
}
public function text_inputCapture(event:TextEvent):void
{
str = txtbox.text; //# Update text to send
txtbox.addEventListener(KeyboardEvent.KEY_DOWN, key_handler);
}
function onSoundLoaded(event:Event):void
{
snd_Chann = snd_Obj.play(); //# Play returned Speech convert result
snd_Obj.removeEventListener(Event.COMPLETE, onSoundLoaded);
}
function onTokenLoaded(evt:Event):void
{ str_Token = evt.target.data; /*# get Token result */ }
} //end Class
} //end Package
This will only work when the SWF file is embedded inside an HTML page. Something like below :
<!DOCTYPE html>
<html>
<body>
<audio id="audio_watson">
<source src="http://stream.watsonplatform.net/text-to-speech/api/v1/synthesize?accept=audio/mp3&text=welcome&voice=en-US_AllisonVoice" type="audio/mpeg">
</audio>
<embed src="Main.swf" width="800" height="600">
<script>
var a = document.getElementById("audio_watson");
a.play(); //playback to trigger authentication
</script>
</body>
</html>
I want to get Call Details from Genesys Platform SIP Server.
And Genesys Platform has Platform SDK for .NET .
Anybod has a SIMPLE sample code which shows how to get call details using Platform SDK for .NET [ C# ] from SIP Server?
Extra Notes:
Call Details : especially i wanted to get AgentId for a given call
and
From Sip Server : I am not sure if Sip Server is the best candiate to
take call details. So open to other suggestions/ alternatives
You can build a class that monitor DN actions. Also you watch specific DN or all DN depending what you had to done. If its all about the call, this is the best way to this.
Firstly, you must define a TServerProtocol, then you must connect via host,port and client info.
var endpoint = new Endpoint(host, port, config);
//Endpoint backupEndpoint = new Endpoint("", 0, config);
protocol = new TServerProtocol(endpoint)
{
ClientName = clientName
};
//Sync. way;
protocol.Open();
//Async way;
protocol.BeginOpen();
I always use async way to do this. I got my reason thou :) You can detect when connection open with event that provided by SDK.
protocol.Opened += new EventHandler(OnProtocolOpened);
protocol.Closed += new EventHandler(OnProtocolClosed);
protocol.Received += new EventHandler(OnMessageReceived);
protocol.Error += new EventHandler(OnProtocolError);
Here there is OnMessageReceived event. This event where the magic happens. You can track all of your call events and DN actions. If you go genesys support site. You'll gonna find a SDK reference manual. On that manual quiet easy to understand there lot of information about references and usage.
So in your case, you want agentid for a call. So you need EventEstablished to do this. You can use this in your recieve event;
var message = ((MessageEventArgs)e).Message;
// your event-handling code goes here
switch (message.Id)
{
case EventEstablished.MessageId:
var eventEstablished = message as EventEstablished;
var AgentID = eventEstablished.AgentID;
break;
}
You can lot of this with this usage. Like dialing, holding on a call inbound or outbound even you can detect internal calls and reporting that genesys platform don't.
I hope this is clear enough.
If you have access to routing strategy and you can edit it. You can add some code to strategy to send the details you need to some web server (for example) or to DB. We do such kind of stuff in our strategy. After successful routing block as a post routing strategy sends values of RTargetPlaceSelected and RTargetAgentSelected.
Try this:
>
Genesyslab.Platform.Contacts.Protocols.ContactServer.Requests.JirayuGetInteractionContent
JirayuGetInteractionContent =
Genesyslab.Platform.Contacts.Protocols.ContactServer.Requests.JirayuGetInteractionContent.Create();
JirayuGetInteractionContent.InteractionId = "004N4aEB63TK000P";
Genesyslab.Platform.Commons.Protocols.IMessage respondingEventY =
contactserverProtocol.Request(JirayuGetInteractionContent);
Genesyslab.Platform.Commons.Collections.KeyValueCollection keyValueCollection =
((Genesyslab.Platform.Contacts.Protocols.ContactServer.Events.EventGetInteractionContent)respondingEventY).InteractionAttributes.AllAttributes;
We are getting AgentID and Place as follows,
Step-1:
Create a Custome Command Class and Add Chain of command In ExtensionSampleModule class as follows,
class LogOnCommand : IElementOfCommand
{
readonly IObjectContainer container;
ILogger log;
ICommandManager commandManager;
public bool Execute(IDictionary<string, object> parameters, IProgressUpdater progress)
{
if (Application.Current.Dispatcher != null && !Application.Current.Dispatcher.CheckAccess())
{
object result = Application.Current.Dispatcher.Invoke(DispatcherPriority.Send, new ExecuteDelegate(Execute), parameters, progress);
return (bool)result;
}
else
{
// Get the parameter
IAgent agent = parameters["EnterpriseAgent"] as IAgent;
IIdentity workMode = parameters["WorkMode"] as IIdentity;
IAgent agentManager = container.Resolve<IAgent>();
Genesyslab.Desktop.Modules.Core.Model.Agents.IPlace place = agentManager.Place;
if (place != null)
{
string Place = place.PlaceName;
}
else
log.Debug("Place object is null");
CfgPerson person = agentManager.ConfPerson;
if (person != null)
{
string AgentID = person.UserName;
log.DebugFormat("Place: {0} ", AgentID);
}
else
log.Debug("AgentID object is null");
}
}
}
// In ExtensionSampleModule
readonly ICommandManager commandManager;
commandManager.InsertCommandToChainOfCommandAfter("MediaVoiceLogOn", "LogOn", new
List<CommandActivator>() { new CommandActivator()
{ CommandType = typeof(LogOnCommand), Name = "OnEventLogOn" } });
enter code here
IInteractionVoice interaction = (IInteractionVoice)e.Value;
switch (interaction.EntrepriseLastInteractionEvent.Id)
{
case EventEstablished.MessageId:
var eventEstablished = interaction.EntrepriseLastInteractionEvent as EventEstablished;
var genesysCallUuid = eventEstablished.CallUuid;
var genesysAgentid = eventEstablished.AgentID;
.
.
.
.
break;
}
I've been using php to create yt live events successfully for a while. Since I've tried to disable embedding I've received the following error:
["Error calling POST https:\/\/www.googleapis.com\/youtube\/v3\/liveBroadcasts?part=snippet%2Cstatus: (400) contentDetails"]
The code is as follows:
$client = new Google_Client();
$client->setClientId($OAUTH2_CLIENT_ID);
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
$client->refreshToken($tokens[0]['google_oauth_refresh_token']);
// Define an object that will be used to make all API requests.
$youtube = new Google_Service_YouTube($client);
// Check to ensure that the access token was successfully acquired.
if ($client->getAccessToken()) {
// die();
// Create an object for the liveBroadcast resource's snippet. Specify values
// for the snippet's title, scheduled start time, and scheduled end time.
$broadcastSnippet = new Google_Service_YouTube_LiveBroadcastSnippet();
$broadcastSnippet->setTitle($_POST['title']);
$broadcastSnippet->setDescription($_POST['description']);
$broadcastSnippet->setScheduledStartTime(date('c', strtotime($_POST['start_date']))); //'2034-01-30T00:00:00.000Z');
$broadcastSnippet->setScheduledEndTime(date('c', strtotime($_POST['start_time']))); // '2034-01-31T00:00:00.000Z');
$contentDetails = new Google_Service_YouTube_LiveBroadcastContentDetails();
$contentDetails->setEnableEmbed(false);
// debug($contentDetails);
// Create an object for the liveBroadcast resource's status, and set the
// broadcast's status to "private".
$status = new Google_Service_YouTube_LiveBroadcastStatus();
// $status->setPrivacyStatus('public');
$status->setPrivacyStatus('private');
// $status->setPrivacyStatus('unlisted');
// Create the API request that inserts the liveBroadcast resource.
$broadcastInsert = new Google_Service_YouTube_LiveBroadcast();
$broadcastInsert->setContentDetails($contentDetails);
$broadcastInsert->setSnippet($broadcastSnippet);
$broadcastInsert->setStatus($status);
$broadcastInsert->setKind('youtube#liveBroadcast');
// Execute the request and return an object that contains information
// about the new broadcast.
$broadcastsResponse = $youtube->liveBroadcasts->insert('snippet,status', $broadcastInsert, array());
// Create an object for the liveStream resource's snippet. Specify a value
// for the snippet's title.
$streamSnippet = new Google_Service_YouTube_LiveStreamSnippet();
$streamSnippet->setTitle('Transcoder - '.$_POST['title']);
// Create an object for content distribution network details for the live
// stream and specify the stream's format and ingestion type.
$cdn = new Google_Service_YouTube_CdnSettings();
$cdn->setFormat("720p");
$cdn->setIngestionType('rtmp');
// Create the API request that inserts the liveStream resource.
$streamInsert = new Google_Service_YouTube_LiveStream();
$streamInsert->setSnippet($streamSnippet);
$streamInsert->setCdn($cdn);
$streamInsert->setKind('youtube#liveStream');
// Execute the request and return an object that contains information
// about the new stream.
$streamsResponse = $youtube->liveStreams->insert('snippet,cdn',
$streamInsert, array());
// debug($streamsResponse);
// Bind the broadcast to the live stream.
$bindBroadcastResponse = $youtube->liveBroadcasts->bind(
$broadcastsResponse['id'],'id,contentDetails',
array(
'streamId' => $streamsResponse['id'],
));
In this line:
$broadcastsResponse = $youtube->liveBroadcasts->insert('snippet,status', $broadcastInsert, array());
It should be:
$broadcastsResponse = $youtube->liveBroadcasts->insert('snippet,status,contentDetails', $broadcastInsert, array());
You are setting contentDetails's embedded property but not including it in the request.
If you read the error, that's what it was complaining.
I am trying to adapt the MvcSiteMapProvider to create the breadcrumb based on some Information stored in a database.
The answer in this post sounded promising so i implemented my own SiteMapNodeProvider. But then i didnt know how to wire things up so the newly implemented SiteMapNodeProvider is used instead of the static xml file ("Mvc.sitemap").
As i am using SimpleInjector in my project, i called the setup method in my already existent Injection-initialization code.
public static void Initialize()
{
Injection.Global = new Container();
InitializeContainer(Injection.Global);
Injection.Global.RegisterMvcControllers(Assembly.GetExecutingAssembly());
Injection.Global.RegisterMvcAttributeFilterProvider();
Injection.Global.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(Injection.Global));
}
private static void InitializeContainer(Container container)
{
// Setup configuration of DI
MvcSiteMapProviderContainerInitializer.SetUp(container);
//... register some other stuff for my project here ...
}
The MvcSiteMapProviderContainerInitializer class got created by the package: 'Mvcsitemapprovider.mvc4.di.simpleinjector/4.4.5'
Does anybody know what to do to make my project use the newly created SiteMapNodeProvider?
I couldnt find any documentation about this in the official docu...
edit: i tried what you suggested (even removed the old DI stuff and only used the one from the nuget-package) but still i am getting errors...
here is what i have in my MvcSiteMapProviderContainerInitializer
public static void SetUp(Container container)
{
bool securityTrimmingEnabled = false;
bool enableLocalization = true;
string absoluteFileName = HostingEnvironment.MapPath("~/Mvc.sitemap");
TimeSpan absoluteCacheExpiration = TimeSpan.FromMinutes(5);
string[] includeAssembliesForScan = new string[] { "testsitemap" };
// Extension to allow resolution of arrays by GetAllInstances (natively based on IEnumerable).
// source from: https://simpleinjector.codeplex.com/wikipage?title=CollectionRegistrationExtensions
AllowToResolveArraysAndLists(container);
var currentAssembly = typeof(MvcSiteMapProviderContainerInitializer).Assembly;
var siteMapProviderAssembly = typeof(SiteMaps).Assembly;
var allAssemblies = new Assembly[] { currentAssembly, siteMapProviderAssembly };
var excludeTypes = new Type[]
{
typeof (SiteMapNodeVisibilityProviderStrategy),
typeof (SiteMapXmlReservedAttributeNameProvider),
typeof (SiteMapBuilderSetStrategy),
typeof (ControllerTypeResolverFactory),
// Added 2013-06-28 by eric-b to avoid default singleton registration:
typeof(XmlSiteMapController),
// Added 2013-06-28 by eric-b for SimpleInjector.Verify method:
typeof(PreservedRouteParameterCollection),
typeof(MvcResolver),
typeof(MvcSiteMapProvider.SiteMap),
typeof(MetaRobotsValueCollection),
typeof(RoleCollection),
typeof(SiteMapPluginProvider),
typeof(ControllerTypeResolver),
typeof(RouteValueDictionary),
typeof(AttributeDictionary)
,typeof(SiteMapNodeCreator)
};
var multipleImplementationTypes = new Type[]
{
typeof (ISiteMapNodeUrlResolver),
typeof (ISiteMapNodeVisibilityProvider),
typeof (IDynamicNodeProvider)
};
// Single implementations of interface with matching name (minus the "I").
CommonConventions.RegisterDefaultConventions(
(interfaceType, implementationType) => container.RegisterSingle(interfaceType, implementationType),
new Assembly[] { siteMapProviderAssembly },
allAssemblies,
excludeTypes,
string.Empty);
// Multiple implementations of strategy based extension points
CommonConventions.RegisterAllImplementationsOfInterfaceSingle(
(interfaceType, implementationTypes) => container.RegisterAll(interfaceType, implementationTypes),
multipleImplementationTypes,
allAssemblies,
new Type[0],
"^Composite");
container.Register<XmlSiteMapController>();
// Visibility Providers
container.RegisterSingle<ISiteMapNodeVisibilityProviderStrategy>(() =>
new SiteMapNodeVisibilityProviderStrategy(
container.GetAllInstances
<ISiteMapNodeVisibilityProvider>().
ToArray(), string.Empty));
// Pass in the global controllerBuilder reference
container.RegisterSingle<ControllerBuilder>(() => ControllerBuilder.Current);
container.RegisterSingle<IControllerBuilder, ControllerBuilderAdaptor>();
container.RegisterSingle<IBuildManager, BuildManagerAdaptor>();
container.RegisterSingle<IControllerTypeResolverFactory>(() =>
new ControllerTypeResolverFactory(new string[0],
container.GetInstance
<IControllerBuilder
>(),
container.GetInstance
<IBuildManager>()));
// Configure Security
container.RegisterAll<IAclModule>(typeof(AuthorizeAttributeAclModule), typeof(XmlRolesAclModule));
container.RegisterSingle<IAclModule>(() => new CompositeAclModule(container.GetAllInstances<IAclModule>().ToArray()));
// Setup cache
container.RegisterSingle<System.Runtime.Caching.ObjectCache>(() => System.Runtime.Caching.MemoryCache.Default);
container.RegisterSingleOpenGeneric(typeof(ICacheProvider<>), typeof(RuntimeCacheProvider<>));
container.RegisterSingle<ICacheDependency>(() => new RuntimeFileCacheDependency(absoluteFileName));
container.RegisterSingle<ICacheDetails>(() => new CacheDetails(absoluteCacheExpiration, TimeSpan.MinValue, container.GetInstance<ICacheDependency>()));
// Configure the visitors
container.RegisterSingle<ISiteMapNodeVisitor, UrlResolvingSiteMapNodeVisitor>();
// Prepare for the sitemap node providers
container.RegisterSingle<ISiteMapXmlReservedAttributeNameProvider>(
() => new SiteMapXmlReservedAttributeNameProvider(new string[0]));
container.RegisterSingle<IXmlSource>(() => new FileXmlSource(absoluteFileName));
// Register the sitemap node providers
container.RegisterSingle<XmlSiteMapNodeProvider>(() => container.GetInstance<XmlSiteMapNodeProviderFactory>()
.Create(container.GetInstance<IXmlSource>()));
container.RegisterSingle<ReflectionSiteMapNodeProvider>(() => container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
.Create(includeAssembliesForScan));
// Register your custom sitemap node provider
container.RegisterSingle<ISiteMapNodeProvider, CustomSiteMapNodeProvider>();
// Register the collection of sitemap node providers (including the custom one)
container.RegisterSingle<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
.Create(new CompositeSiteMapNodeProvider(
container.GetInstance<XmlSiteMapNodeProvider>(),
container.GetInstance<ReflectionSiteMapNodeProvider>(),
container.GetInstance<CustomSiteMapNodeProvider>())));
container.RegisterAll<ISiteMapBuilderSet>(ResolveISiteMapBuilderSets(container, securityTrimmingEnabled, enableLocalization));
container.RegisterSingle<ISiteMapBuilderSetStrategy>(() => new SiteMapBuilderSetStrategy(container.GetAllInstances<ISiteMapBuilderSet>().ToArray()));
}
private static IEnumerable<ISiteMapBuilderSet> ResolveISiteMapBuilderSets(Container container, bool securityTrimmingEnabled, bool enableLocalization)
{
yield return new SiteMapBuilderSet(
"default",
securityTrimmingEnabled,
enableLocalization,
container.GetInstance<ISiteMapBuilder>(),
container.GetInstance<ICacheDetails>());
}
private static void AllowToResolveArraysAndLists(Container container)
{
container.ResolveUnregisteredType += (sender, e) =>
{
var serviceType = e.UnregisteredServiceType;
if (serviceType.IsArray)
{
RegisterArrayResolver(e, container,
serviceType.GetElementType());
}
else if (serviceType.IsGenericType &&
serviceType.GetGenericTypeDefinition() == typeof(IList<>))
{
RegisterArrayResolver(e, container,
serviceType.GetGenericArguments()[0]);
}
};
}
private static void RegisterArrayResolver(UnregisteredTypeEventArgs e, Container container, Type elementType)
{
var producer = container.GetRegistration(typeof(IEnumerable<>)
.MakeGenericType(elementType));
var enumerableExpression = producer.BuildExpression();
var arrayMethod = typeof(Enumerable).GetMethod("ToArray")
.MakeGenericMethod(elementType);
var arrayExpression = Expression.Call(arrayMethod, enumerableExpression);
e.Register(arrayExpression);
}
}
but still i get the following exception:
No registration for type DynamicSiteMapNodeBuilder could be found and
an implicit registration could not be made. The constructor of the
type DynamicSiteMapNodeBuilder contains the parameter of type
ISiteMapNodeCreator with name 'siteMapNodeCreator' that is not
registered. Please ensure ISiteMapNodeCreator is registered in the
container, or change the constructor of DynamicSiteMapNodeBuilder.
First of all, to integrate with an existing DI setup, you should install MvcSiteMapProvider.MVC4.DI.SimpleInjector.Modules instead of MvcSiteMapProvider.MVC4.DI.SimpleInjector. You can downgrade by running this command from package manager console:
PM> Uninstall-Package -Id MvcSiteMapProvider.MVC4.DI.SimpleInjector
Be sure NOT to uninstall any dependencies. This will ensure that you don't have 2 sets of DI initialization code in your project - there should only be 1 for the entire application.
Next, you need to wire up for DI as well as some other initialization code required by MvcSiteMapProvider. The readme file contains instructions how to do this. Here is how you would do it with your existing configuration.
public static void Initialize()
{
Injection.Global = new Container();
InitializeContainer(Injection.Global);
Injection.Global.RegisterMvcControllers(Assembly.GetExecutingAssembly());
Injection.Global.RegisterMvcAttributeFilterProvider();
Injection.Global.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(Injection.Global));
}
private static void InitializeContainer(Container container)
{
// Setup configuration of DI (required)
MvcSiteMapProviderContainerInitializer.SetUp(container);
// Setup global sitemap loader (required)
MvcSiteMapProvider.SiteMaps.Loader = container.GetInstance<ISiteMapLoader>();
// Check all configured .sitemap files to ensure they follow the XSD for MvcSiteMapProvider (optional)
var validator = container.GetInstance<ISiteMapXmlValidator>();
validator.ValidateXml(HostingEnvironment.MapPath("~/Mvc.sitemap"));
// Register the Sitemaps routes for search engines (optional)
XmlSiteMapController.RegisterRoutes(RouteTable.Routes); // NOTE: You can put this in your RouteConfig.cs file if desired.
//... register some other stuff for your project here ...
}
If the /sitemap.xml endpoint doesn't work, you may also need to add this line to register the XmlSiteMapController:
Injection.Global.RegisterMvcControllers(typeof(MvcSiteMapProvider.SiteMaps).Assembly);
To implement ISiteMapNodeProvider, there is an example here: MvcSiteMapProvider ISiteMapBuilder in conjunction with IDynamicNodeProvider.
To register your custom ISiteMapNodeProvider, you just need to ensure it gets added to the constructor of SiteMapBuilder. You can also exclude the existing SiteMapNodeProviders from the code below depending on your needs.
// Register the sitemap node providers
container.RegisterSingle<XmlSiteMapNodeProvider>(() => container.GetInstance<XmlSiteMapNodeProviderFactory>()
.Create(container.GetInstance<IXmlSource>()));
container.RegisterSingle<ReflectionSiteMapNodeProvider>(() => container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
.Create(includeAssembliesForScan));
// Register your custom sitemap node provider
container.RegisterSingle<ISiteMapNodeProvider, CustomSiteMapNodeProvider>();
// Register the collection of sitemap node providers (including the custom one)
container.RegisterSingle<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
.Create(new CompositeSiteMapNodeProvider(
container.GetInstance<XmlSiteMapNodeProvider>(),
container.GetInstance<ReflectionSiteMapNodeProvider>(),
container.GetInstance<CustomSiteMapNodeProvider>())));
Do note that IDynamicNodeProvider (which is documented) does almost exactly the same thing as ISiteMapNodeProvider, so you could use that option instead. There are 3 main differences:
With IDynamicNodeProvider, you must create a "template" node that defines the dynamicNodeProvider attribute, and the template node itself won't be included in the SiteMap, so it must be used in conjunction with a ISiteMapNodeProvider implementation that processes the dynamic nodes (the built-in ISiteMapNodeProviders do this automatically).
IDynamicNodeProvider doesn't need to be part of the DI setup because it is already processed by both XmlSiteMapNodeProvider and ReflectionSiteMapNodeProvider.
With ISiteMapNodeProvider, you are working directly with the ISiteMapNode object, with IDynamicNodeProvider you are working with an abstraction (DynamicNodeProvider) and there is a conversion that happens automatically.
About SimpleInjector.Verify
If you want Verify() to work, you need to add the following to the excludeTypes array in the MvcSiteMapProviderContainerInitializer.
typeof(SiteMapNodeCreator),
typeof(DynamicSiteMapNodeBuilder)
I have added them to the module and will be in the next version of the Nuget package, but these modules do not update so you have to do it manually.
Note that the Verify() method tries to create an instance of everything that is registered with the container - including objects that never get created by the container in the real world. Therefore, if you use the Verify() method you have to be more diligent that something is not accidentally registered. This makes convention-based registration more difficult to do.
I would like to pull stories from Agile Zen using their REST API.
I read:
http://help.agilezen.com/kb/api/overview
http://help.agilezen.com/kb/api/security
Also, I got this to work: http://groovy.codehaus.org/HTTP+Builder
How would one combine the above in order to get Groovy client code to access AgileZen stories?
Here is the code sample which makes one story with id of 1 show up for a specific project whose id is 16854:
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.JSON
public class StoryGetter {
public static void main(String[] args) {
new StoryGetter().getStories()
}
void getStories() {
// http://agilezen.com/project/16854/story/4
// /api/v1/project/16854/story/2
def http = new HTTPBuilder( 'http://agilezen.com' )
http.request( GET, JSON ) {
uri.path = '/api/v1/project/16854/story/1'
headers.'X-Zen-ApiKey' = 'PUT YOUR OWN API KEY HERE'
response.success = { resp, json ->
println "json size is " + json.size()
println json.toString()
}
}
}
}
I had to put in a fake API key in this post since I should not share my API key.
(By the way, this is not using SSL. A follow up question in regards to doing this for a SSL enabled project may come soon.)